AsyncTask is an Android mechanism created to help handle long operations that need to report to the UI thread. To take advantage of this class, we need to create a new subclass of AsyncTask
and implement its doInBackground()
, onProgressUpdate()
, and onPostExecute()
methods. In other words, we are going to fill in the blanks for what to do in the background, what to do when there’s some progress, and what to do when the task completes.
Time consuming jobs such as big data processing, database or network accessing that run in UI thread may cause an ANR error (application not responding). The best solution to avoid ANR (Application not responding) error is using a worker thread running parallel with UI thread.
Before you start using the AsyncTask
class, you'll need to understand the lifecycle compared to running an operation on the main thread.
The first method that is called by an AsyncTask
is onPreExecute()
. This method runs on the UI thread and is meant for setting up any interface components that need to let the user know that something is happening.
After onPreExecute()
has finished, doInBackground(T)
is called. The generic parameter here is any information that you need to pass to the method for it to perform its task. For example, if you're writing a task that retrieves JSON from a URL, you would pass the URL to this method as a String. As an operation makes progress in doInBackground()
, you can call onProgressUpdate(T)
to update your UI (such as a progress bar on the screen). Here the generic is a value representing the progress, such as an Integer
.
Once the doInBackground()
method has completed, it can return an object that is passed into onPostExecute(T)
, such as a JSONObject that was downloaded from our initial URL. onPostExecute(T)
runs on the UI thread.
The following are the four AsyncTask functions that can be used:
doInBackground
– This is the main working function. If progress update is necessary, the publishProgress
can be called, which will finally leads to the calling of onProgressUpdate
. isCancelled()
can be used to test the state of thread, so as to do the job properly.onProgressUpdate
– This method is invoked by calling publishProgress
anytime from doInBackground
call this method. UI update should only be done in this function. onPreExecute
– This is called before doInBackground
.onPostExecute
– This is called after doInBackground
. Result from doInBackground
is passed to this method.AsyncTask is a template class which takes three type arguments: the first is the type for argument of doInBackground
; the second is the type for the argument of onProgressUpdate
; the third is the type for the argument onPostExecute
. These three functions each have an input argument of vargars type.
Bellow is simple example with AsyncTask. There are LinearLayout with a Button and a WebView. Click on Button will load page to WebView in AsyncTask. Very simple example but it give all "gotcha".
Here is activity_main.xml with LinearLayout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/btnLoad" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="loadPage" android:text="Load page"> </Button> <WebView android:id="@+id/wvPage" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
Following is MainActivity
public class MainActivity extends Activity { final Context context = this; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void loadPage(View view) { LoadPage task = new LoadPage(); task.execute(new String[] {"http://proft.me"}); } private class LoadPage extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... urls) { WebView wv = (WebView) findViewById(R.id.wvPage); wv.loadUrl(urls[0]); return null; } @Override protected void onPostExecute(String result) { Toast.makeText(MainActivity.this, "Page loaded", Toast.LENGTH_SHORT).show(); } } }
Following is example of anonymous AsyncTask
with simple task
new AsyncTask<Void, Void, Void>() { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Void doInBackground(Void... params) { // task GlideApp.get(context).clearDiskCache(); return null; } @Override protected void onPostExecute(Void result) {} }.execute();
There is a issue when starting an AsyncTask
and then rotating the screen. If you attempt to reference a Context
item (such as a View
or Activity
) after the original Context
has been destroyed, an Exception
will be thrown. The easiest way around this is to call cancel(true)
on your AsyncTask
in your Activity or Fragment's onDestroy()
method, and then validate that the task hasn't been canceled in onPostExecute(T)
.
AsyncTask
is impractical for some use cases:
AsyncTask
is running, for example if the user changes the screen orientation, the activity that created the AsyncTask
is destroyed and re-created. The AsyncTask
is unable to access the newly created activity, and the results of the AsyncTask
aren't published.AsyncTask
objects stay around, and your app may run out of memory or crash. If the activity that created the AsyncTask
is destroyed, the AsyncTask
is not destroyed along with it. For example, if your user exits the application after the AsyncTask
has started, the AsyncTask
keeps using resources unless you call cancel()
.When to use AsyncTask:
For all other situations, use AsyncTaskLoader
, which is part of the Loader
framework.
Useful links