Welcome Friends !!
Most of the time it is very difficult to understand how we are going to handle the async task in application development. The heavy task like downloading a image from the internet or other networking task should not be done from the main thread.
I am going to write an article that describes the usage of Threads, Handlers and AsyncTask in your application. It also covers how to handle the application lifecycle together with threads. It is based on Eclipse 4.2, Java 1.6 and Android 4.2.
1. Android's user interface thread
Android modifies the user interface and handles input events from one single user interface thread. This thread is also called the main thread.
Android collects all events in a queue and processed an instance of the
Looper class.
If the programmer does not use any concurrency constructs, all code of an Android application runs in the main thread and every statement is executed after each other.
If you perform a long lasting operation, for example accessing data from the Internet, the application blocks until the corresponding operation has finished.
To provide a good user experience all potentially slow running operations in an Android application should run asynchronously, e.g. via some way of concurrency constructs of the Java language or the Android framework. This includes all potential slow operations, like network, file and database access and complex calculations.
2. Using Java threads in Android
Android supports the usage of the
Thread class to perform asynchronous processing.
Android also supplies the
java.util.concurrent package to perform something in the background, e.g. using theThreadPools and Executor classes.
If you need to update the user interface from a new
Thread, you need to synchronize with the user interface thread.
If you use Java threads you have to handle the following requirements
in your own code:
- Synchronization with the main thread if you post back results to the user interface
- No default for canceling the thread
- No default thread pooling
- No default for handling configuration changes in Android
Android provides additional constructs to handle concurrently in comparison with standard Java. You can use the
android.os.Handler class or the AsyncTasks classes. More sophisticated approach are based on the Loader class, retained Fragments and services.
The
Handler class can be used to register to a thread and provides a simple channel to send data to this thread.
A
Handler object registers itself with the thread in which it is created. For example, if you create a new instance of the Handler class in the onCreate() method of your activity, the resulting Handler object can be used to post data to the main thread.
The data which can be posted via the
Handler class can be an instance of the Message or the Runnable class.4.2. Creating and reusing instances of Handlers
To use a handler you have to subclass it and override the
handleMessage() method to process messages.
Your thread can post messages via the
sendMessage(Message) method or via the sendEmptyMessage() method to theHandler object.
To process a
Runnable you can use the post() method.
To avoid object creation you can also reuse the existing
Handler object of your activity.// Reuse existing handler if you don't // have to override the message processing handler = getWindow().getDecorView().getHandler();
The
View class allows you to post objects of type Runnable via the post() method.
The following code demonstrates the usage of a
Handler via a View.
Assume your activity uses the following layout.
<?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" > <ProgressBar android:id="@+id/progressBar1" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:indeterminate="false" android:max="10" android:padding="4dip" > </ProgressBar> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" > </TextView> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="startProgress" android:text="Start Progress" > </Button> </LinearLayout>
With the following the
ProgressBar get updated once the users presses the Button.import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; public class ProgressTestActivity extends Activity { private ProgressBar progress; private TextView text; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); progress = (ProgressBar) findViewById(R.id.progressBar1); text = (TextView) findViewById(R.id.textView1); } public void startProgress(View view) { // do something long Runnable runnable = new Runnable() { @Override public void run() { for (int i = 0; i <= 10; i++) { final int value = i; doFakeWork(); progress.post(new Runnable() { @Override public void run() { text.setText("Updating"); progress.setProgress(value); } }); } } }; new Thread(runnable).start(); } // Simulating something timeconsuming private void doFakeWork() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }
5. AsyncTask
The
AsyncTask class encapsulates the creation of a background process and the synchronization with the main thread. It also supports reporting progress of the running tasks.
To use
AsyncTask you must subclass it. AsyncTask uses generics and varargs. The parameters are the following AsyncTask <TypeOfVarArgParams , ProgressValue , ResultValue> .
An
AsyncTask is started via the execute() method.
The
execute() method calls the doInBackground() and the onPostExecute() method.
TypeOfVarArgParams is passed into the
doInBackground() method as input, ProgressValue is used for progress information and ResultValue must be returned from doInBackground() method and is passed to onPostExecute() as a parameter.
The
doInBackground() method contains the coding instruction which should be performed in a background thread. This method runs automatically in a separate Thread.
The
onPostExecute() method synchronizes itself again with the user interface thread and allows it to be updated. This method is called by the framework once the doInBackground() method finishes.
Android executes
AsyncTask tasks before Android 1.6 and again as of Android 3.0 in sequence by default.
You can tell Android to run it in parallel with the usage of the
executeOnExecutor() method, specifyingAsyncTask.THREAD_POOL_EXECUTOR as first parameter.
The following code snippet demonstrates that.
// ImageLoader extends AsyncTask ImageLoader imageLoader = new ImageLoader(imageView); // Execute in parallel imageLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "http://url.com/image.png");
The
AsyncTask does not handle configuration changes automatically, i.e. if the activity is recreated, the programmer has to handle that in his coding.
A common solution to this is to declare the
AsyncTask in a retained headless fragment.
The following code demonstrates how to use the
AsyncTask class to download the content of a webpage.
Create a new Android project called de.vogella.android.asynctask with an activity called ReadWebpageAsyncTask. Add the
android.permission.INTERNET permission to your AndroidManifest.xml file.
Create the following layout.
<?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/readWebpage" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onClick" android:text="Load Webpage" > </Button> <TextView android:id="@+id/TextView01" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Placeholder" > </TextView> </LinearLayout>
Change your activity to the following:
import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import de.vogella.android.asyntask.R; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.TextView; public class ReadWebpageAsyncTask extends Activity { private TextView textView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textView = (TextView) findViewById(R.id.TextView01); } private class DownloadWebPageTask extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... urls) { String response = ""; for (String url : urls) { DefaultHttpClient client = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); try { HttpResponse execute = client.execute(httpGet); InputStream content = execute.getEntity().getContent(); BufferedReader buffer = new BufferedReader(new InputStreamReader(content)); String s = ""; while ((s = buffer.readLine()) != null) { response += s; } } catch (Exception e) { e.printStackTrace(); } } return response; } @Override protected void onPostExecute(String result) { textView.setText(result); } } public void onClick(View view) { DownloadWebPageTask task = new DownloadWebPageTask(); task.execute(new String[] { "http://www.vogella.com" }); } }
If you run your application and press your button then the content of the defined webpage is read in the background. Once this process is done your
TextView is updated.