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.