Is AsyncTask really conceptually flawed or am I just missing something? Is AsyncTask really conceptually flawed or am I just missing something? android android

Is AsyncTask really conceptually flawed or am I just missing something?


How about something like this:

class MyActivity extends Activity {    Worker mWorker;    static class Worker extends AsyncTask<URL, Integer, Long> {        MyActivity mActivity;        Worker(MyActivity activity) {            mActivity = activity;        }        @Override        protected Long doInBackground(URL... urls) {            int count = urls.length;            long totalSize = 0;            for (int i = 0; i < count; i++) {                totalSize += Downloader.downloadFile(urls[i]);                publishProgress((int) ((i / (float) count) * 100));            }            return totalSize;        }        @Override        protected void onProgressUpdate(Integer... progress) {            if (mActivity != null) {                mActivity.setProgressPercent(progress[0]);            }        }        @Override        protected void onPostExecute(Long result) {            if (mActivity != null) {                mActivity.showDialog("Downloaded " + result + " bytes");            }        }    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mWorker = (Worker)getLastNonConfigurationInstance();        if (mWorker != null) {            mWorker.mActivity = this;        }        ...    }    @Override    public Object onRetainNonConfigurationInstance() {        return mWorker;    }    @Override    protected void onDestroy() {        super.onDestroy();        if (mWorker != null) {            mWorker.mActivity = null;        }    }    void startWork() {        mWorker = new Worker(this);        mWorker.execute(...);    }}


The reason is obvious: what if the activity gets destroyed which triggered the task?

Manually disassociate the activity from the AsyncTask in onDestroy(). Manually re-associate the new activity to the AsyncTask in onCreate(). This requires either a static inner class or a standard Java class, plus perhaps 10 lines of code.


It looks like AsyncTask is a bit more than just conceptually flawed. It is also unusable by compatibility issues. The Android docs read:

When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting HONEYCOMB, tasks are back to being executed on a single thread to avoid common application errors caused by parallel execution. If you truly want parallel execution, you can use the executeOnExecutor(Executor, Params...) version of this method with THREAD_POOL_EXECUTOR; however, see commentary there for warnings on its use.

Both executeOnExecutor() and THREAD_POOL_EXECUTOR are Added in API level 11 (Android 3.0.x, HONEYCOMB).

This means that if you create two AsyncTasks to download two files, the 2nd download will not start until the first one finishes. If you chat via two servers, and the first server is down, you will not connect to the second one before the connection to the first one times out. (Unless you use the new API11 features, of course, but this will make your code incompatible with 2.x).

And if you want to target both 2.x and 3.0+, the stuff becomes really tricky.

In addition, the docs say:

Caution: Another problem you might encounter when using a worker thread is unexpected restarts in your activity due to a runtime configuration change (such as when the user changes the screen orientation), which may destroy your worker thread. To see how you can persist your task during one of these restarts and how to properly cancel the task when the activity is destroyed, see the source code for the Shelves sample application.