8

my issue is the same as this Instance variable of Activity not being set in onPostExecute of AsyncTask or how to return data from AsyncTask to main UI thread but i want to send the data back to the same calling activity. Doesnt startActivity for intents always restart the activity

Community
  • 1
  • 1
skinnybrit51
  • 4,927
  • 7
  • 25
  • 28

2 Answers2

16

On option is to use listeners, where you create an interface that your activity implents, something like:

public interface AsyncListener {
    public void doStuff( MyObject obj );
}

That way, if you're subclassing AsyncTask, it is easy to add this listener, then in onPostExecute(), you could do something like:

protected void onPostExecute( MyObject obj ) {
   asyncListener.doStuff(obj);
}
Mike D
  • 4,938
  • 6
  • 43
  • 99
7

This depends on your class structure, but if your AsyncTask is a class within your Activity then you can reference methods of that activity. What you would do is in your onPostExecute method call a function of your Activity that passes some data that was retrieved in the AsyncTask to the activity where you can then use it..

The code would look like this

class YourActivity extends Activity {
   private static final int DIALOG_LOADING = 1;

   public void onCreate(Bundle savedState) {
     setContentView(R.layout.yourlayout);
     showDialog(DIALOG_LOADING);     
     new LongRunningTask1().execute(1,2,3);

   } 

   protected Dialog onCreateDialog(int dialogId) {
     switch(dialogId) {
       case DIALOG_LOADING:
           ProgressDialog pDialog = new ProgressDialog(this);
           pDialog.setTitle("Loading Data");
           pDialog.setMessage("Loading Data, please wait...");
           return pDialog;
        default:
            return super.onCreateDialog(dialogId);
      }      
   }

   private void onBackgroundTaskDataObtained(List<String> results) {
      dismissDialog(DIALOG_LOADING);
     //do stuff with the results here..
   }

   private class LongRunningTask extends AsyncTask<Long, Integer, List<String>> {
        @Override
        protected void onPreExecute() {
          //do pre execute stuff
        }

        @Override
        protected List<String> doInBackground(Long... params) {
            List<String> myData = new ArrayList<String>(); 
            for (int i = 0; i < params.length; i++) {
                try {
                    Thread.sleep(params[i] * 1000);
                    myData.add("Some Data" + i);
                } catch(InterruptedException ex) {
                }                
            }
            return myData;
        }

        @Override
        protected void onPostExecute(List<String> result) {
            YourActivity.this.onBackgroundTaskDataObtained(result);
        }    
    }

}

So the typical flow is like this, set the view of the current page, and then show a progress dialog. Right after that start the async task (or whenever, it doesn't matter really).

After your async task is complete, call a function of the activity and pass it the data. Don't use shared data within the async task or you risk issues with threading.. Instead once you are done with it pass it to the activity. If you want to update the view progressively while doing work you can use on onProgressUpdate

Matt Wolfe
  • 8,924
  • 8
  • 60
  • 77
  • 1
    Thank you for your answer. I am not a fan of AsyncTask being used as a sub class. I would think you should be able to use events. I think the answer is using intents but I this will only create a new instance of my activity which I dont want. – skinnybrit51 Feb 25 '12 at 20:45
  • You can easily use your AsyncTask in its own class, but that is only useful if you are using that same logic from multiple different activities.. In which case you could either: 1. use a common base class (not activity but something extending activity) and then you'd have a common method which could be called from the async task. Or better yet have them both implement a common interface which has the callback as I described. Pass a reference to the activity into the constructor of the AsyncTask and make sure the asyncTask has a constructor which takes a parameter of the interface type. – Matt Wolfe Feb 25 '12 at 20:49
  • Your last option is to ditch AsyncTask altogether and put this into a service which you need to create a new thread for to do the background activity (since services won't run in there own thread by default). An easy way to do this is to create an IntentService which creates a new thread for you. – Matt Wolfe Feb 25 '12 at 20:51
  • http://mobile.tutsplus.com/tutorials/android/android-fundamentals-intentservice-basics/ I have built my own awhile back but eventually I changed it from being an intent service to a regular service. The main issue with services is that communication between activities is a bit more complicated (lots of options). What you might do is give more specifics about what you are trying to accomplish and ask in a new thread if an asynctask or service/intentservice would be the better option. – Matt Wolfe Feb 25 '12 at 21:35