Android 4
22. Threads and AsyncTask
This chapter
- 22.0 Threads
- 22.1 Threads Using Handler - Example 1
- 22.2 Threads Using Handler - Example 2
- 22.3 AsyncTask
A Thread is a concurrent unit of execution. It has its own call stack for methods being invoked, their arguments and local variables. Each virtual machine instance has at least one main Thread running when it is started; typically, there are several others for housekeeping. The application might decide to launch additional Threads for specific purposes.
Threads in the same VM interact and synchronize by the use of shared objects and monitors associated with these objects. Synchronized methods and part of the API in Object also allow Threads to cooperate.
There are basically two main ways of having a Thread execute application code:
- One is providing a new class that extends Thread and overriding its run() method.
- The other is providing a new Thread instance with a Runnable object during its creation. In both cases, the start() method must be called to actually execute the new Thread.
See http://developer.android.com/reference/java/lang/Thread.html
or
http://www.bogotobogo.com/Java/tutorial/threads.php
The recommended method of spawning a thread is to implementing the interface of java.lang.Runnable as shown in the following example:
package com.bogotobogo.myrunnablethread; class MyRunnable implements Runnable { public void run() { System.out.println("Spawned thread " + Thread.currentThread().getName()); } } public class TestingThread { public static void main(String[] args) { new Thread (new MyRunnable()).start(); System.out.println("Main thread " + Thread.currentThread().getName()); } }
If we run the code, we get:
Spawned thread Thread-0 Main thread main
The TestingThread creats a new thread, passing the instance of MyRunnable to the thread constructor. Then, it calls start() on the new thread. When the start() method of the thread is called, the underlying virtual machine will create a new oncurrent thread of execution, which will, in turn, call the run()
method of the passed Runnable, executing it in parallel with the spawning thread. At this point, the virtual machine is running two independent processes; order of execution and timing in one thread are unrelated to order and timing in the other.The class Thread is not final, and it is possible to define a new, concurrent task by subclassing Thread and overriding its run() method. However, there is no advantage to that approach.
We want our Android application to be downright snappy. End users are used to responsive apps on the mobile and any small delay is perceived as un-responsiveness or worse they may think the application has hung. Responding to user input quickly typically within in 200 milliseconds should be our goal. At least, we need to make sure we respond within less than 5 seconds. If a main thread is blocked for more than 5 seconds the user is presented with the infamous application not responding (ANR) dialog.
So, what is a thread?
Whenever we start an Android application, a thread called main is automatically created. The main thread, also called the UI thread, is very important because it is in charge of dispatching the events to the appropriate widgets and this includes the drawing events. It is also the thread we interact with Android widgets on. For instance, if we touch the a button on screen, the UI thread dispatches the touch event to the widget which in turn sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues the request and notifies the widget to redraw itself.
The main Java code, SingleThread.java, looks like this:
package com.bogotobogo.singlethread; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class SingleThread extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button start = (Button) findViewById(R.id.thread_button); start.setOnClickListener(new OnClickListener() { public void onClick(View view) { try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } }
main.xml;
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/thread_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/thread_button" /> </LinearLayout>
strings.xml;
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Sleeping, SingleThread!</string> <string name="app_name">SingleThread</string> <string name="thread_button">Testing Responses</string> </resources>
The button will remain in its pressed state for about 5 seconds:
before going back to its normal state.
When this happens, it is very easy for the user to perceive the application as slow.
One of the basic principles to provide a very responsive application is to handle any time consuming code in a separate thread so that we can avoid lengthy operations on the UI thread. We must use extra threads (background or worker threads) to perform these operations.
Android provides a few ways to set up background threads, yet allow them to safely interact with the UI on the UI thread.
The safely interact is crucial. We cannot modify any part of the UI from a background thread. It must be done on the UI thread. This generally means that there will need to be some coordination between background threads doing the work and the UI thread showing the results of that work.
Let's take the example of a click listener downloading an image over the network and displaying it in an ImageView:
public void onClick(View v) { new Thread(new Runnable() { public void run() { Bitmap b = loadImageFromNetwork(); mImageView.setImageBitmap(b); } }).start(); }
At first, this code seems to be a good solution to our problem, as it does not block the UI thread. Unfortunately, it violates the single thread model: the Android UI toolkit is not thread-safe and must always be manipulated on the UI thread. In this piece of code, the ImageView is manipulated on a worker thread, which can cause really weird problems. Tracking down and fixing such bugs can be difficult and time-consuming.
Android UI is event-driven, built on a library of nestable components, and single-threaded. Because a GUI must respond to asynchronous events from multiple sources, it is nearly impossible to avoid deadlock if the UI is multithreaded. A single thread owns both the input (touch screen, keypad, and so on) and output devices and executes request from each, sequentially, usually in the order they were received.
While UI runs on a single thread, most of Android application will be multithreaded. The UI must respond to the user and animate the display regardless of whether the code that retrieves data from the network is currently processing incoming data. The UI must be quick and responsive and cannot be ordered with respect to other, long-running processes. The long-running processes must be run asynchronously.
Android offers several ways to access the UI thread from other threads. We may already be familiar with some of them but here is a comprehensive list:
- Activity.runOnUiThread(Runnable)
- View.post(Runnable)
- View.postDelayed(Runnable, long)
- Handler
The most flexible ways of making an Android-friendly background thread is to create an instance of a Handler subclass. We need only one object per activity, and we do not need to manually register it. Just creating the instance is sufficient to register it with the Android threading subsystem.
So, it is very essential to understand about how to create new threads (worker or background threads) and how to come back to the parent thread.
How do the two threads, parent/UI and the worker threads, communicate? Via the Handler.
A Handler allows us 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.
So, let us take the handler from the main thread and see how we can use it to communicate with a child thread.
When a handler is created, it is associated by default with the current thread. So, we have this piece of code in the main activity class:
package com.bogotobogo.handlerthread; import android.app.Activity; import android.app.ProgressDialog; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class HandlerThread extends Activity{ private ProgressDialog progressDialog; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ((Button) findViewById(R.id.Button01)) .setOnClickListener(new OnClickListener() { public void onClick(View view) { DoSomething(); } }); } private Handler messageHandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); progressDialog.dismiss(); } }; }
Now, on click of the button, the DoSomething() method is invoked. Assuming that this is a very time consuming task, we're creating a thread and do the task and return from that thread as shown in the code below:
protected void DoSomething() { // TODO Auto-generated method stub progressDialog = ProgressDialog.show(this, "", "Doing something..."); new Thread() { public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { } messageHandler.sendEmptyMessage(0); } }.start(); }
Since it is time consuming, we're starting a ProgressDialog just to inform the end user that some activity is happening. Then, we start the thread, make it sleep for 5000 milliseconds and send back an empty message through the message handler. The messageHandler.sendEmptyMessage(0) is the callback on the parent thread's messageHandler to inform that the child thread has finished its work. In this example, we're sending an empty message. But this can be the means of communication and exchange of data from the child thread to the parent Thread.
Now the control returns to handleMessage() call back method. That method shown in the beginning just dismisses the progressDialog.
Files used in this thread via handler example, HandlerThread.zip
Here is another similar example with a Java code:
package com.bogotobogo.handlerthreadb; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.ProgressBar; public class HandlerThreadB extends Activity { ProgressBar bar; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); bar=(ProgressBar)findViewById(R.id.progress); } public void onStart() { super.onStart(); bar.setProgress(0); new Thread(new Runnable() { public void run() { try { for (int i=0;i<50;i++) { Thread.sleep(1000); handler.sendEmptyMessage(0); } } catch (Throwable t) { } } }).start(); } Handler handler=new Handler() { @Override public void handleMessage(Message msg) { bar.incrementProgressBy(2); } }; }
We create an instance of Handler and it has implementation handleMessage(). Actually for any message received, we update the ProgressBar by 2 poins, and then exit the message handler.
In onStart(), we set up a background thread. This thread does something.
Files used in this thread via handler example B, HandlerThreadB.zip
One convenient tool for implementing an asynchronous task in the Android is called AsyncTask.
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers. In other words, Android will handle all of the chores of doing work on the UI thread not on a background thread. Also, Android itself allocates and removes that background thread. Actually, AsyncTask hides many of the details of the threads used to run the task.
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. In general, AsyncTask takes a set of parameters and returns a result. Because the parameters have to be passed between threads and the result returned between threads, handshaking is required to ensure thread safety.
An AsyncTask is invoked by calling its execute() method with parameters. Those parameters are eventually passed on to the doInBackground() method, when it runs on a background thread. In turn, doInBackground() produces a result. The AsyncTask mechanism returns that result by passing it as the argument to doPostExecute(), run in the same thread as the original execute().
An asynchronous task is defined by 3 generic types, called Params, Progress and Result,
and 4 steps, called begin, doInBackground, processProgress and end.
The detail information about the three types used by an asynchronous task are the following:
- Params the type of the parameters sent to the task upon execution.
- Progress the type of the progress units published during the background computation.
- Result the type of the result of the background computation.
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
When an asynchronous task is executed, the task goes through 4 steps:
(http://developer.android.com/reference/android/os/AsyncTask.html)
- onPreExecute() invoked on the UI thread immediately after the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
- doInBackground(Params...) invoked on the background thread immediately after onPreExecute(), finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...), to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
- onProgressUpdate(Progress...) invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
- doPostExecute(Result) invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
There are a few threading rules that must be followed for this class to work properly:
- The task instance must be created on the UI thread.
- Do not call
onPreExecute(), onPostExecute(Result), doInBackground(Params...),
onProgressUpdate(Progress...) manually. - The task can be executed only once (an exception will be thrown if a second execution is attempted.)
This example is an implementation of a ListActivity that uses an AsyncTask.
In this example, rather than simply pass the list of Java book to an ArrayAdapter, we simulate needing to work to create these list in the background using AddStringTask. Our AsyncTask, the AddStringTask a sublass of AsyncTask, will override at least one method doInBackground(Params...), and most often will override a second one onPostExecute(Result).
Let's look at our code,AsyncThrea.java:
package com.bogotobogo.threadc; import android.app.ListActivity; import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; import android.widget.ArrayAdapter; import android.widget.Toast; import java.util.ArrayList; public class ThreadAsync extends ListActivity { private static String[] items={ "Hello, Android: Introducing Google's Mobile Development Platform ", "Professional Android 4 Application Development ", "Unlocking Android: A Developer's Guide", "Android Application Development: Programming with the Google SDK", "Pro Android 4", "Beginning Android 4", "Android Programming Tutorials, 3rd Edition", "Android Wireless Application Development", "Pro Android Games", "Beginning Smartphone Web Development", "The Busy Coder's Guide to Advanced Android Development", "Head First Java, 3rd Edition", "Effective Java (3rdd Edition)", "Sams Teach Yourself Java in 24 Hours (5th Edition)", "Core Java(TM), Volume I--Fundamentals (8th Edition)", "Java In A Nutshell, 5th Edition", "Thinking in Java (4th Edition)", "Java Concurrency in Practice", "SCJP Sun Certified Programmer for Java 7 Exam 310-065", "Java How to Program, 7th Edition", "Learning Java", "Head First Design Patterns", "Beginning Java EE 7 Platform with GlassFish 3", "Head First Servlets and JSP", "Java Message Service", "Core Java(TM), Volume I--Fundamentals (9th Edition)", "Beginning Programming with Java For Dummies" }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); setListAdapter( new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>())); new AddStringTask().execute(); } class AddStringTask extends AsyncTask<Void, String, Void> { @Override protected Void doInBackground(Void... unused) { for (String item : items) { publishProgress(item); SystemClock.sleep(200); } return(null); } @Override protected void onProgressUpdate(String... item) { ((ArrayAdapter<String>)getListAdapter()).add(item[0]); } @Override protected void onPostExecute(Void unused) { Toast.makeText(ThreadAsync.this, "Done - Finished updating Java Book List!", Toast.LENGTH_SHORT).show(); } } }
Let's look at the AddStringTask:
class AddStringTask extends AsyncTask{
We want to pass each string generated by our background task to onProgressUpdate() because we want to add it to our list. So, our second type should be String while others are void types.
The doInBackground() method:
@Override protected Void doInBackground(Void... unused) { for (String item : items) { publishProgress(item); SystemClock.sleep(200); } return(null); }
This method is invoked in a background thread. Here, we iterate over our list of books, the call publishProgress(item) for each item. Then, make it sleep 1/4 second to simulate real work being done.
onProgressUpdate() method:
@Override protected void onProgressUpdate(String... item) { ((ArrayAdapter<String>)getListAdapter()).add(item[0]); }
This method is called on the UI thread, and we want to do something to let the user know we are making progress on loading these strings. In this case, we simply add the string to the ArrayAdapter, so it is appended to the end of the list.
onProgressUpdate(String... ) receives a String... varargs because that is the second data type in our class declaration. Since we are passing only one string per call to onProgressUpdate(), we need to examine just first entry in the varargs array.
The onPostExecute() method is called on the UI thread, and we want to do something to indicate that the background work is complete. Here we simply raise a Toast.
The last thing we look at is :
new AddStringTask().execute();
To use AddStringTask(), we just create an instance and call execute() on it. That starts the chain of events eventually leading to the background thread doing its work.
Time to run our application.
Files used in this thread via handler example B, ThreadAsync.zip
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization