Question

I am currently working with the tab host and fragment. Currently I set fragment a to download json A and fragment B to download json B , the problem is when I switch fragment, the fragment A onPostExecute function will fall into the fragment B one , is there any way to fix this? Thanks

Tab host:

tabHost = (FragmentTabHost) findViewById(R.id.tabhost);
        tabHost.setup(this, getSupportFragmentManager(), R.id.tabcontent);
        tabHost.addTab(
                tabHost.newTabSpec("Home").setIndicator("",
                        res.getDrawable(R.drawable.btn_about)), Home.class,
                null);
        tabHost.addTab(
                tabHost.newTabSpec("About").setIndicator("",
                        res.getDrawable(R.drawable.btn_about)), About.class,
                null);

The async task

public class JSONReader {
    public static final String TAG = "JSONReader";
    public ArrayList<Record> records;
    public Record myRecordObj;
    public ArrayList<GalleryImage> images;
    public String url;
    public int failCount = 0; // retry twice
    public Context ctx;
    public String readCase;

    public JSONReader(String _url, Context _ctx , String _readCase) {
        url = _url;
        ctx = _ctx;
        readCase = _readCase;
    }

    public void getJSON() {
        new JSONDownload().execute(url);
    }

    private class JSONDownload extends AsyncTask<String, Void, JSONObject> {
        // TODO Auto-generated method stub
        StringBuilder builder = new StringBuilder();
        String temp = "";
        String json = ""; // json content
        InputStream input = null;
        OutputStream output = null;
        HttpURLConnection connection = null;

        @Override
        protected JSONObject doInBackground(String... params) {
            // TODO Auto-generated method stub

            try {
                Log.d(TAG, "Start reading: " + url);
                URL url = new URL(params[0]);
                connection = (HttpURLConnection) url.openConnection();
                connection.connect();

                if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
                    return null;
                // return "Server returned HTTP " + connection.getResponseCode()
                // + " " + connection.getResponseMessage();

                input = connection.getInputStream();

                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(input));

                while ((temp = reader.readLine()) != null) {
                    builder.append(temp);
                }

                json = builder.toString();
            } catch (Exception e) {
                return null;
            } finally {
                try {
                    if (input != null)
                        input.close();
                    if (output != null)
                        output.close();
                } catch (IOException ignored) {
                }
                if (connection != null)
                    connection.disconnect();
            }

            try {
                return new JSONObject(json);
            } catch (JSONException e) {
                e.printStackTrace();
                return null;
            }
        }

        @Override
        protected void onPostExecute(JSONObject result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            onJSONDownloaded(result);
        }

    }

    public void onJSONDownloaded(JSONObject result) {
        // TODO Auto-generated method stub
        if (result != null) {

            failCount = 0;

            if (readCase.equals("leaderBoard")){
                records = new ArrayList<Record>();

                try {
                    JSONObject myRecord = result.getJSONObject("myRecord");

                    if (myRecord != null) {
                        myRecordObj = new Record(myRecord.getString("pic"),myRecord.getString("name"),myRecord.getString("score"));
                    }

                    JSONArray topRecords = result.getJSONArray("topRecord");

                    for (int i = 0; i < topRecords.length(); i++) {
                        JSONObject topRecord = topRecords.getJSONObject(i);
                        String topName = topRecord.getString("name");
                        String topPic = topRecord.getString("pic");
                        String topScore = topRecord.getString("score");
                        records.add(new Record(topPic, topName, topScore));
                    }

                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                ((LeaderBoardDetail)ctx).setData(records,myRecordObj);
            } else if (readCase.equals("galleryList")){
                images = new ArrayList<GalleryImage>();

                try {
                    JSONArray imageList = result.getJSONArray("images");
                    for (int i = 0; i < imageList.length(); i++) {
                        JSONObject image = imageList.getJSONObject(i);
                        images.add(new GalleryImage(image.getString("url"),image.getString("thumbUrl"),image.getString("category"),image.getString("userPic"),image.getString("name")));
                    }
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                //exception
                if (((FragmentActivity) ctx).getSupportFragmentManager().findFragmentById(R.id.tabcontent).getTag().equals("Gallery")) {
                    PhotoGallery galleryFragment = (PhotoGallery) ((FragmentActivity) ctx).getSupportFragmentManager().findFragmentById(R.id.tabcontent);
                    galleryFragment.setData(images);
                }

            }

        } else {
            if (failCount <= 1) { // check global_conf twice if fail
                failCount++;
                Log.d(TAG, "No of retry" + failCount);
                new JSONDownload().execute(url); // Retry download json
            } else {
                failCount = 0;
            }
        }
    }
}
Was it helpful?

Solution

I used it in my app this way which works for me and answer is a bit similar to another answer but few additions and more detail. Hope it help you too.

NOTE: This is just a idea, u need to try, it may vary as per your app architect.

At your activity make the task object global [make sure set task obj null once task is finish]

 JSDownload js = null;

public void getJSON() {

 if(js != null && js.getStatus() == AsyncTask.Status.RUNNING) 
 { 
   js.cancel(true);  
   if(js.isCancelled())
   {
     js = new JSONDownload();
     js.execute(url);
   }
   else
   {

     js = new JSONDownload();
     js.execute(url);  
   }
  }

At the Async class side....[make sure u take care null result @ onpostExcute]

class JSONDownload extends AsyncTask<String, Void, JSONObject> 
{
    protected JSONObject doInBackground(String... params) {
        // TODO Auto-generated method stub
        try {

            if(!this.isCancelled())
         {
               //make http connection ..
             URL url = new URL(params[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();


           //as we are in steps in bg check iscancel .. again 
          //if its a loop here we call break; and return null once only..
          if(this.isCancelled())
                   return null;
         // connection status check and get buffer etc .. code here

            if(this.isCancelled()) 
              return null;

         //read data 
        return data;
      }

     }  catch (Exception e) {
            return null;
        } 
   }


  @Override
   protected void onCancelled(){
 // If you write your own implementation, do not call super.onCancelled(result). 
  }
 }

OTHER TIPS

Use the global async task variable

LongOperation LongOperationOdeme = new LongOperation();

and set:

LongOperationOdeme.cancel(true);

This will stop any async task running at that moment, it's what the back button does

If you are not looking for a simplest answer but for a maybe more interesting and elegant, have a peek at this article, especially if you find functional programming interesting.

It's easier than it looks, i was almost unfamiliar to FP before this article but it covers common problems related to AsyncTask and asynchronicity in Android in general, so I got the gist and consider to use Observables instead of AsyncTask in the future projects myself. It is RxJava and it can solve your problem gracefully: "The fromFragment call transforms the given source observable in such a way that events will only be emitted to the fragment if it’s still alive and attached to its host activity."

One more citation form the article: "What if the user decides to back out of the Activity that triggered the task, and we are holding on to a stale reference. This not only creates a substantial memory leak, but is also worthless because meanwhile it has been detached from the application window. A problem that everyone is well aware of."

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top