Question

In one of my Activities I do have up to six different AsyncTasks that may run on different events. All AsyncTasks handle orientation changes gracefully (at least I hope so). In onRetainNonConfigurationInstance() I do return the AsyncTask object of a currently running AsyncTask. Later, during onCreate(), I need to find out what AsyncTask object is returned from getLastNonConfigurationInstance().

I use the Activity context in all onPostExecute() methods to get the new activity (if there is a new one). I found this concept here on StackOverflow and did modify it a little bit because I don't like that "Trash running tasks on orientation change" paradigma. Hope this concept is correct.

In the code shown below you'll find two different AsyncTasks. During onRetainNonConfigurationInstance() I will return the currently running AsyncTask. My problem is within onCreate(). How to find out what object is returned? What AsyncTask was running when orientation change bumped in?

Both AsyncTasks are different in many areas (not shown here) so I didn't use an own extended AsyncTask base object.

Many thanks in advance.

public class MyActivity extends ListActivity {
    // First AsyncTask
    private class MyLoadAsyncTask extends AsyncTask<Void, Void, Cursor> {

        private MyActivity       context;
        private MyProgressDialog dialog;

        public MyLoadAsyncTask(MyActivity context) {
            super();

            this.context = context;
        }

        @Override
        protected Cursor doInBackground(Void... voids) {
            return MyApplication.getSqliteOpenHelper().fetchSoomething();
        }

        @Override
        protected void onPostExecute(Cursor cursor) {
            if (dialog != null) {
                dialog.dismiss();
                dialog = null;
            }

            if (cursor != null) {
                context.startManagingCursor(cursor);
                context.adapter = new InternetradiosAdapter(context,
                                                            R.layout.row,
                                                            cursor,
                                                            new String[] { "text1",
                                                                           "text2" },
                                                            new int[] { R.id.row_text1,
                                                                        R.id.row_text2 } );
                if (context.adapter != null) {
                    context.setListAdapter(context.adapter);
                }
            }

            context.loadTask = null;
        }

        @Override
        protected void onPreExecute () {
            dialog = MyProgressDialog.show(context, null, null, true, false);
        }
    }

    private class MyDeleteAsyncTask extends AsyncTask<Void, Void, Boolean> {
        // Second AsyncTask
        private MyActivity       context;
        private MyProgressDialog dialog;
        private long             id;

        public MyDeleteAsyncTask(MyActivity context, long id) {
            super();

            this.context = context;
            this.id = id;
        }

        @Override
        protected Boolean doInBackground(Void... voids) {
            return MyApplication.getSqliteOpenHelper().deleteSomething(id);
        }

        @Override
        protected void onPostExecute(Boolean result) {
            if (dialog != null) {
                dialog.dismiss();
                dialog = null;
            }

            if (result) {
                context.doRefresh();
            }

            context.deleteTask = null;
        }

        @Override
        protected void onPreExecute () {
            dialog = MyProgressDialog.show(context, null, null, true, false);
        }
    }

    private MyDeleteAsyncTask deleteTask;
    private MyLoadAsyncTask   loadTask;

    @Override
    public void onCreate(Bundle bundle) {
        // ...
        // What Task is returned by getLastNonConfigurationInstance()?
        // ...
        // xxxTask = (MyXxxAsyncTask) getLastNonConfigurationInstance();
        // ...
        if (deleteTask != null) {
            deleteTask.context = this;
            deleteTask.dialog = MyProgressDialog.show(this, null, null, true, false);
        } else if (loadTask != null) {
            loadTask.context = this;
            loadTask.dialog = MyProgressDialog.show(this, null, null, true, false);
        } else {
            loadTask = new MyLoadAsyncTask(this);
            loadTask.execute();
        }
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        if (deleteTask != null) {
            if (deleteTask.dialog != null) {
                deleteTask.dialog.dismiss();
                deleteTask.dialog = null;
                return deleteTask;
            }
        } else if (loadTask != null) {
            if (loadTask.dialog != null) {
                loadTask.dialog.dismiss();
                loadTask.dialog = null;
                return loadTask;
            }

        return null;
    }
}
Was it helpful?

Solution

In your onCreate() add:

    Object savedInstance = getLastNonConfigurationInstance();
    if(savedInstance instanceof MyDeleteAsyncTask){
        //it's a MyDeleteAsyncTask
    }else if(savedInstance instanceof MyLoadAsyncTask){
        //it's a MyLoadAsyncTask
    }

OTHER TIPS

I've found that the best way to deal with activities that have multiple running AsyncTasks inside of them is to actually return an object that contains all of the running ones and automatically reinitialize all of their contexts in onCreate(). E.g.

private class AsyncTaskList() {
  List<ActivityTask> tasks; //interface all of your AsyncTasks implement
  public void addTask() { /* add to list*/ }
  public void completeTask { /* remove from list */ }
  public void attachContext(Activity activity) {
    for ( ActivityTask task : tasks) {
      //You can also check the type here and do specific initialization for each AsyncTask
      task.attachContext(activity);
    }
  }
}

public void onCreate(Bundle bundle) {
  AsyncTaskList taskList = (AsyncTaskList) getLastNonConfigurationInstance();
  if (taskList != null) {
    taskList.attachContext(this);
  }
  ...
}

Now you just need to add and remove the tasks when they start/finish.

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