Note that there are some explanatory texts on larger screens.

plurals
  1. POStop an AsyncTask on tab switch
    primarykey
    data
    text
    <p>I have an Android application that has 3 tabs; they're created using an Activity (TabsFragmentActivity), and the interfaces for each tab are created using Fragments (TabProfile, TabSearch, and TabLocations fragments). </p> <p>In one of my fragments (TabLocations), I start an AsyncTask. I want to be able to cancel the AsyncTask once the user switches to a different tab. Is there a way for me to do this through the Activity (TabsFragmentActivity) that populates the tabs? </p> <p>I think what I need to do is check on the status of the AsyncTask from the TabsFragmentActivity activity, but I'm not sure how to do this since the AsyncTask is initiated in one of the fragments and not the activity itself. The issue I have now is that at the async task, it tries to populate some listviews, and the listviews aren't on the screen if the user switches tabs.</p> <p><strong>TabFragmentActivity.java</strong></p> <pre><code>package com.example.q; import java.util.HashMap; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.View; import android.widget.TabHost; import android.widget.TabHost.TabContentFactory; import com.parse.Parse; import com.parse.ParseACL; import com.parse.ParseUser; public class TabsFragmentActivity extends FragmentActivity implements TabHost.OnTabChangeListener { private static final String TAG = "TabsFragmentActivity"; private TabHost mTabHost; private HashMap mapTabInfo = new HashMap(); private TabInfo mLastTab = null; private class TabInfo { private String tag; private Class clss; private Bundle args; private Fragment fragment; TabInfo(String tag, Class clazz, Bundle args) { this.tag = tag; this.clss = clazz; this.args = args; } } class TabFactory implements TabContentFactory { private final Context mContext; /** * @param context */ public TabFactory(Context context) { mContext = context; } /** (non-Javadoc) * @see android.widget.TabHost.TabContentFactory#createTabContent(java.lang.String) */ public View createTabContent(String tag) { View v = new View(mContext); v.setMinimumWidth(0); v.setMinimumHeight(0); return v; } } /** (non-Javadoc) * @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle) */ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Step 1: Inflate layout setContentView(R.layout.tabs_layout); // Step 2: Setup TabHost initialiseTabHost(savedInstanceState); mTabHost.setCurrentTab(1); if (savedInstanceState != null) { //mTabHost.setCurrentTab(1); mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); //set the tab as per the saved state } // initialize Parse Log.d(TAG, "initializing Parse"); Parse.initialize(this, "rReToGbnCSdQEi7Q33UrCO4U395Rk7RcKPcNncOn", "haJKaN0zbNKhgBT1t9jGUY0ih4rYQfPMA9p31BSw"); ParseUser.enableAutomaticUser(); ParseACL defaultACL = new ParseACL(); // If you would like all objects to be private by default, remove this line. defaultACL.setPublicReadAccess(true); ParseACL.setDefaultACL(defaultACL, true); } /** (non-Javadoc) * @see android.support.v4.app.FragmentActivity#onSaveInstanceState(android.os.Bundle) */ protected void onSaveInstanceState(Bundle outState) { outState.putString("tab", mTabHost.getCurrentTabTag()); //save the tab selected super.onSaveInstanceState(outState); } /** * Step 2: Setup TabHost */ private void initialiseTabHost(Bundle args) { mTabHost = (TabHost)findViewById(android.R.id.tabhost); mTabHost.setup(); TabInfo tabInfo = null; TabsFragmentActivity.addTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab1"). setIndicator("", getResources().getDrawable(R.drawable.profile)), (tabInfo = new TabInfo("Tab1", TabProfile.class, args))); this.mapTabInfo.put(tabInfo.tag, tabInfo); TabsFragmentActivity.addTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab2"). setIndicator("", getResources().getDrawable(R.drawable.locations) ), (tabInfo = new TabInfo("Tab2", TabLocations.class, args))); this.mapTabInfo.put(tabInfo.tag, tabInfo); TabsFragmentActivity.addTab(this, this.mTabHost, this.mTabHost.newTabSpec("Tab3"). setIndicator("", getResources().getDrawable(R.drawable.search)), (tabInfo = new TabInfo("Tab3", TabSearch.class, args))); this.mapTabInfo.put(tabInfo.tag, tabInfo); // Default to the second tab this.onTabChanged("Tab2"); mTabHost.setOnTabChangedListener(this); } /** * @param activity * @param tabHost * @param tabSpec * @param clss * @param args */ private static void addTab(TabsFragmentActivity activity, TabHost tabHost, TabHost.TabSpec tabSpec, TabInfo tabInfo) { // Attach a Tab view factory to the spec tabSpec.setContent(activity.new TabFactory(activity)); String tag = tabSpec.getTag(); // Check to see if we already have a fragment for this tab, probably // from a previously saved state. If so, deactivate it, because our // initial state is that a tab isn't shown. tabInfo.fragment = activity.getSupportFragmentManager().findFragmentByTag(tag); if (tabInfo.fragment != null &amp;&amp; !tabInfo.fragment.isDetached()) { FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction(); ft.detach(tabInfo.fragment); ft.commit(); activity.getSupportFragmentManager().executePendingTransactions(); } tabHost.addTab(tabSpec); } /** (non-Javadoc) * @see android.widget.TabHost.OnTabChangeListener#onTabChanged(java.lang.String) */ public void onTabChanged(String tag) { Log.d(TAG, "in onTabChanged"); TabInfo newTab = (TabInfo) this.mapTabInfo.get(tag); if (mLastTab != newTab) { Log.d(TAG, "switching to new tab"); FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction(); if (mLastTab != null) { Log.d(TAG, "last tab not null"); if (mLastTab.fragment != null) { Log.d(TAG, "last tab fragment not null"); ft.detach(mLastTab.fragment); } } if (newTab != null) { if (newTab.fragment == null) { newTab.fragment = Fragment.instantiate(this, newTab.clss.getName(), newTab.args); ft.add(R.id.realtabcontent, newTab.fragment, newTab.tag); } else { ft.attach(newTab.fragment); } } mLastTab = newTab; ft.commit(); this.getSupportFragmentManager().executePendingTransactions(); } } } </code></pre> <p><strong>TabLocations.java</strong> (There is a lot in this file, so I've edited most out for clarity):</p> <pre><code>public class TabLocations extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (container == null) { return null; } return (RelativeLayout)inflater.inflate(R.layout.tab_locations_layout, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { // Run AsyncTask for getting Google Places FetchGooglePlaces places = new FetchGooglePlaces(getActivity()); places.execute(); } } </code></pre> <p><strong>FetchGooglePlaces.java</strong> - my AsyncTask</p> <pre><code>package com.example.q; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import android.app.Activity; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.Toast; import com.parse.FindCallback; import com.parse.GetCallback; import com.parse.ParseException; import com.parse.ParseObject; import com.parse.ParseQuery; public class FetchGooglePlaces extends AsyncTask&lt;String, PlacesList, String&gt;{ private static final String TAG = "FetchGooglePlaces"; // Google Places GooglePlaces googlePlaces; // Places List public PlacesList nearPlaces; // GPS Location GPSTracker gps; // Progress layouts for qlocations and alocations LinearLayout qProgress; LinearLayout aProgress; // KEY Strings public static String KEY_REFERENCE = "reference"; // id of the place public static String KEY_NAME = "name"; // name of the place // ListView of all q locations detected ListView qLV; // ListView of all all non-q locations detected ListView allLV; // Refresh Button Button refresh; // TabLocations activity public Activity activity; PlacesDBHelper placesDBHelper; SQLiteDatabase db; // ArrayList to store the names of qLocations ArrayList&lt;String[]&gt; qLocations; //ArrayList for storing QLocations ArrayList&lt;QLocation&gt; qLocationData = new ArrayList&lt;QLocation&gt;(); //Temporary ArrayList for storing QLocations ArrayList&lt;String[]&gt; qLocationDataString = new ArrayList&lt;String[]&gt;(); //ArrayList for storing allLocations ArrayList&lt;QLocation&gt; allLocationData = new ArrayList&lt;QLocation&gt;(); //Temporary ArrayList for storing allLocations ArrayList&lt;String[]&gt; allLocationDataString = new ArrayList&lt;String[]&gt;(); boolean done = false; boolean checking = true; int counter = 0; public FetchGooglePlaces(Activity a){ activity = a; } /** * Before starting background thread Show Progress Dialog * */ @Override protected void onPreExecute() { super.onPreExecute(); // placesDBHelper = new PlacesDBHelper(activity); // Log.d(TAG, "attempting to create database"); // // Log.d(TAG, "placesDBHelper: " + placesDBHelper.getDatabaseName()); // set visibility of progress bars qProgress = (LinearLayout) activity.findViewById(R.id.lin_progressBar); qProgress.setVisibility(View.VISIBLE); aProgress = (LinearLayout) activity.findViewById(R.id.lin_progressBar2); aProgress.setVisibility(View.VISIBLE); // creating GPS Class object gps = new GPSTracker(activity); } /** * getting Places JSON * */ protected String doInBackground(String... args) { // creating Places class object googlePlaces = new GooglePlaces(); try { Log.d(TAG, "getting google places"); String types = "cafe|restaurant"; // Listing places only cafes, restaurants // Radius in meters - increase this value if you don't find any places double radius = 1000; // 1000 meters // get nearest places nearPlaces = googlePlaces.search(gps.getLatitude(), gps.getLongitude(), radius, types); } catch (Exception e) { e.printStackTrace(); } return null; } /** * After completing background task Dismiss the progress dialog * and show the data in UI * Always use runOnUiThread(new Runnable()) to update UI from background * thread, otherwise you will get error * **/ protected void onPostExecute(String file_url) { Log.d(TAG, "complete"); /** * Updating parsed Places into LISTVIEW * */ // Get json response status String status = nearPlaces.status; // Check for all possible status if(status.equals("OK")){ // Successfully got places details if (nearPlaces.results != null) { // get current list of Q Locations + their wait times qLocations = new ArrayList&lt;String[]&gt;(); ParseQuery qs = new ParseQuery("QLocations"); //EDIT: THIS SHOULD ONLY QUERY LOCATIONS THAT ARE CLOSEBY (TO MINIMIZE SEARCH TIME) qs.findInBackground(new FindCallback() { @Override public void done(final List&lt;ParseObject&gt; qList, ParseException e) { if (e==null){ // add each parse location to the qLocations array for(int i= 0; i &lt; qList.size(); i++){ if(checking){ final String name = qList.get(i).getString("name"); checking = false; //get queue length for each location ParseObject place = qList.get(i); place.getParseObject("Line").fetchIfNeededInBackground(new GetCallback() { @Override public void done(ParseObject object, ParseException e) { String lineLength = Integer.toString(object.getInt("length")); String[] locationArray = new String[] {name, lineLength}; qLocations.add(locationArray); //Log.d(TAG, "added " + qLocations.get(qLocations.size()-1)[0] + " to qLocations"); counter++; if (counter == qList.size()){ drawListViews(); } } }); checking = true; } } } else{ Log.d("Error", "Error: " + e.getMessage()); } } }); } } else{ Toast.makeText(activity, "Google Places Error!", Toast.LENGTH_SHORT); } } public void drawListViews(){ Log.d(TAG, "in drawListViews()"); // loop through each place int counter = 0; for (Place p : nearPlaces.results) { //limit to 10 search results if (counter&lt;9){ HashMap&lt;String, String&gt; map = new HashMap&lt;String, String&gt;(); // Place reference won't display in listview - it will be hidden // Place reference is used to get "place full details" map.put(KEY_REFERENCE, p.reference); // Place name map.put(KEY_NAME, p.name); boolean placeExists = false; String lineLength = ""; for(int i=0; i&lt;qLocations.size(); i++){ // if the google places exists as a Q if (p.name.equals(qLocations.get(i)[0])){ placeExists = true; lineLength = qLocations.get(i)[1]; break; } } if (placeExists){ // add to qLocationData array qLocationDataString.add(new String[] {p.name, p.reference, lineLength}); }else{ // add to allLocationData array allLocationDataString.add(new String[] {p.name, p.reference, lineLength}); } }else{ break; } counter++; } //sort qLocationDataString by length of line Collections.sort(qLocationDataString, new Comparator&lt;String[]&gt;(){ public int compare(String[] strings, String[] otherStrings){ return Integer.valueOf(strings[2]).compareTo(Integer.valueOf(otherStrings[2])); } }); // add sorted qLocationDataString to qLocationData to pass to the array adapter for(int i=0; i&lt;qLocationDataString.size(); i++){ qLocationData.add(new QLocation(qLocationDataString.get(i)[0], qLocationDataString.get(i)[1], qLocationDataString.get(i)[2] )); } //sort allLocationDataString alphabetically Collections.sort(allLocationDataString, new Comparator&lt;String[]&gt;(){ public int compare(String[] strings, String[] otherStrings){ return strings[0].compareTo(otherStrings[0]); } }); // add sorted allLocationDataString to allLocationData to pass to the array adapter for(int i=0; i&lt;allLocationDataString.size(); i++){ allLocationData.add(new QLocation(allLocationDataString.get(i)[0], allLocationDataString.get(i)[1], allLocationDataString.get(i)[2] )); } // Getting qListView: List View for locations with Qs qLV = (ListView) activity.findViewById(R.id.qListView); // list adapter ListAdapter qAdapter = new QAdapter(activity, R.layout.google_places_item, qLocationData, "qs"); // Adding data into listview qLV.setAdapter(qAdapter); // Getting allListView: List View for locations without Qs allLV = (ListView) activity.findViewById(R.id.allListView); // list adapter ListAdapter allAdapter = new QAdapter(activity, R.layout.google_places_item, allLocationData, "all"); // Adding data into listview allLV.setAdapter(allAdapter); // hide progress bars qProgress.setVisibility(View.GONE); aProgress.setVisibility(View.GONE); // // show refresh button // refresh = (Button) activity.findViewById(R.id.refreshButton); // refresh.setVisibility(View.VISIBLE); returnPlaces(nearPlaces); Button maps = (Button) activity.findViewById(R.id.btn_show_map); /** Button click event for showing map */ maps.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d("attempting to create new intent", "show map"); Intent i = new Intent(activity, QMapActivity.class); // Sending user current geo location i.putExtra("user_latitude", Double.toString(gps.getLatitude())); i.putExtra("user_longitude", Double.toString(gps.getLongitude())); // passing near places to map activity i.putExtra("near_places", nearPlaces); // pass list of q locations to map activity i.putExtra("q_places", qLocationDataString); Log.d(TAG, nearPlaces.toString()); // staring activity activity.startActivity(i); } }); } private PlacesList returnPlaces(PlacesList places){ return places; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload