Android Threads and Handlers

Introduction

 
This tutorial describes the usage of Threads and Handlers in your application. It also covers how to handle the application lifecycle together with threads.
 
Threads
 
When an application is launched, the system creates a thread of execution for the application, called "main".
 
This thread is very important because it is in charge of dispatching events to the appropriate user interface widgets, including drawing events. It is also the thread in which your application interacts with components from the Android UI toolkit (components from the android.widget and android.view packages). As such, the main thread is also sometimes called the UI thread.
 
The system does not create a separate thread for each instance of a component. All components that run in the same process are instantiated in the UI thread, and system calls to each component are dispatched from that thread
 
When your app performs intensive work in response to user interaction, this single thread model can yield poor performance unless you implement your application properly. Specifically, if everything is happening in the UI thread, performing long operations such as network access or database queries will block the whole UI. When the thread is blocked, no events can be dispatched, including drawing events. From the user's perspective, the application appears to hang.
 
Even worse, if the UI thread is blocked for more than a few seconds (about 5 seconds currently) the user is presented with the infamous "application not responding" (ANR) dialog. The user might then decide to quit your application and uninstall it if they are unhappy.
 
Additionally, the Andoid UI toolkit is not thread-safe. So, you must not manipulate your UI from a worker thread - you must do all manipulation to your user interface from the UI thread.
 
Handler
 
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it - from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
 
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
 
When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will then be scheduled in the Handler's message queue and processed when appropriate.
 
In this article we will use first scenario.
 
Tutorial: Threads & Handler
 
In this example we use the Handler class to handle a ProgressDialog and ImageView in a background Thread.
 
We will display a ProgressDialog with the message "Image Downloading" until the Thread finishes its work of image downloading. After downloading the image, if the image is successfully downloaded, we will show it, otherwise we will show an "Error" like image on the screen.
 
Step 1
 
Create a new Android project called "Handler" with the following statistics.
 
Project Build Target: Android 2.3 or higher
 
Package Name: com.test
 
Activity Name: HandlerActivity
 
Step 2
 
Open your "AandroidManifest" file and add the following code to it.
 
We need to use the permission "Internet". So add the following line:
 
<uses-permission android:name="android.permission.INTERNET"/>
 
Now, your manifest file will look like this.
 
AndroidManifest.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.       package="com.test"  
  4.       android:versionCode="1"  
  5.       android:versionName="1.0">  
  6.     <uses-sdk android:minSdkVersion="9" />  
  7.                 <uses-permission android:name="android.permission.INTERNET"/>  
  8.    
  9. <application  
  10. android:icon="@drawable/icon"      android:label="@string/app_name">  
  11.         <activity android:name=".HandlerActivity"  
  12.                   android:label="@string/app_name">  
  13.             <intent-filter>  
  14.                 <action android:name="android.intent.action.MAIN" />  
  15.                 <category android:name="android.intent.category.LAUNCHER" />  
  16.             </intent-filter>  
  17.         </activity>  
  18.    
  19.     </application>  
  20. </manifest> 
Step 3
 
We need to use an ImageView which shows an image after downloading.
 
Put an "error" image inside the "drawable" directory. An error image will be shown if we fail to download the image from the internet.
 
Threads-Handler.jpg
 
Main.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"  
  6.     >  
  7.                 <ImageView  
  8.                                 android:layout_height="wrap_content"  
  9.                                 android:layout_width="wrap_content"  
  10.                                 android:id="@+id/imageView1"  
  11.                 />  
  12. </LinearLayout> 
Step 4
 
Now, we will start the coding of the HandlerActivity.
 
Open your HandlerActivity file, and enter the following code. In the code, I wrote all the relevant information in the comments to help you understand.
 
HandlerActivity.java
  1. import java.io.IOException;  
  2.    
  3. import org.apache.http.HttpEntity;  
  4. import org.apache.http.HttpResponse;  
  5. import org.apache.http.StatusLine;  
  6. import org.apache.http.client.ClientProtocolException;  
  7. import org.apache.http.client.HttpClient;  
  8. import org.apache.http.client.methods.HttpGet;  
  9. import org.apache.http.client.methods.HttpUriRequest;  
  10. import org.apache.http.impl.client.DefaultHttpClient;  
  11. import org.apache.http.util.EntityUtils;  
  12.    
  13. import android.app.Activity;  
  14. import android.app.ProgressDialog;  
  15. import android.graphics.Bitmap;  
  16. import android.graphics.BitmapFactory;  
  17. import android.os.Bundle;  
  18. import android.os.Handler;  
  19. import android.widget.ImageView;  
  20.    
  21. public class HandlerActivity extends Activity  
  22. {  
  23.     Handler handler;  
  24.       ProgressDialog dialog;  
  25.       Bitmap bitmap;  
  26.       ImageView imageView;  
  27.        
  28.       /** Called when the activity is first created. */  
  29.     @Override  
  30.     public void onCreate(Bundle savedInstanceState)  
  31.     {  
  32.         super.onCreate(savedInstanceState);  
  33.         setContentView(R.layout.main);  
  34.          
  35.         /*take reference of ImageView*/  
  36.         imageView = (ImageView)findViewById(R.id.imageView1);  
  37.          
  38.         /*initialize handler*/  
  39.         handler = new Handler();  
  40.          
  41.         /*create new Progressdialog*/  
  42.         dialog = new ProgressDialog(this);  
  43.          
  44.         /*set title of dialog*/  
  45.         dialog.setTitle("Processing");  
  46.          
  47.         /*set message you want to display to user*/  
  48.         dialog.setMessage("Downloading Image...");  
  49.          
  50.         /*whether dialog disappear on "Back" button press or not*/  
  51.         dialog.setCancelable(true);  
  52.          
  53.         /*finally show dialog on the screen*/  
  54.         dialog.show();  
  55.          
  56.         /* 
  57.          * create a new thread to download image 
  58.          * Note : if you want any error, pass wrong image url 
  59.         */  
  60.         MyThread thread = new MyThread("http://www.hcs.harvard.edu/csharp/Logo1.png");  
  61.         thread.start();  
  62.          
  63.     }  
  64.      
  65.     public class MyThread extends Thread  
  66.     {  
  67.       String url;  
  68.       public MyThread(String url)  
  69.       {  
  70.             this.url=url;  
  71.       }  
  72.        
  73.             @Override  
  74.         public void run()  
  75.         {  
  76.             try  
  77.             {  
  78.              
  79.             /*provides convenience methods to access request properties */  
  80.             HttpUriRequest request = new HttpGet(url);  
  81.              
  82.             /*Interface for an HTTP client*/  
  83.           HttpClient httpClient = new DefaultHttpClient();  
  84.            
  85.           /*To handle response of HttpClient Request*/  
  86.           HttpResponse response;  
  87.              
  88.             response = httpClient.execute(request);  
  89.              
  90.             /*Represents a status line as returned from a HTTP server*/  
  91.           StatusLine statusLine = response.getStatusLine();  
  92.            
  93.           /*take status code of response*/  
  94.           int statusCode = statusLine.getStatusCode();  
  95.            
  96.           //If Successful  
  97.           if (statusCode == 200)  
  98.           {  
  99.             /*entity that received with an HTTP message*/  
  100.             HttpEntity entity = response.getEntity();  
  101.              
  102.             /*get bytes from entity*/  
  103.             byte[] bytes = EntityUtils.toByteArray(entity);  
  104.              
  105.             /*decode bytes into bitmap*/  
  106.             bitmap = BitmapFactory.decodeByteArray(bytes, 0,bytes.length);  
  107.           }  
  108.           /*if status code is other then 200 means that there is some problem*/  
  109.           else  
  110.           {  
  111.             bitmap=null;  
  112.           }  
  113.            
  114.             } catch (ClientProtocolException e) {  
  115.                   e.printStackTrace();  
  116.             } catch (IOException e) {  
  117.                   e.printStackTrace();  
  118.             }  
  119.              
  120.             /*Causes the Runnable to be added to the message queue*/  
  121.             handler.post(new Runnable()  
  122.             {  
  123.                   @Override  
  124.                   public void run()  
  125.                   {  
  126.                          
  127.                   /*if image successfully download*/  
  128.                   if(bitmap!=null)  
  129.                         imageView.setImageBitmap(bitmap);  
  130.                   else  
  131.                         imageView.setImageResource(R.drawable.symbol_error);  
  132.                    
  133.                   /* 
  134.                    * Though we made dialog setCancelable(true), user can 
  135.                    * cancel dialog, but thread will continue running in 
  136.                    * background, so we need to check whether dialog is 
  137.                    * currently showing to the screen or not.  
  138.                   */  
  139.                   if(dialog.isShowing())  
  140.                         dialog.dismiss();  
  141.                    
  142.                   }  
  143.             });  
  144.                    
  145.             }  
  146.        
  147.     }  
Step 5
 
Right-click your project -> Run -> Run Configuration
 
android-run-configuration.jpg
 
Your IP address is your internet address, which you can get using the "ipconfig" command or from the status of your network connection. Your IP address and Port are inside the field excluding the "<" and ">" symbols.
 
Step 6
 
Run your application. (You must have a device or emulator or 2.3 API.)
 
The following is a successful download output:
 
application-run-android
 
If you pass the wrong URL of the image:
 
wrong-url-of-image-android.jpg
 

Summary

 
In this tutorial, we learn how to use Threads in Android applications and how to integrate with the UI thread.


Similar Articles