Multi Threading in Android

It is good practice to not do computation intensive work on the UI Thread. In fact starting from HoneyComb, you get a NetworkOnMainThread exception if you try and do any network processing on the main thread. So we should do background work in a new thread. One thing we need to consider is that only the UI thread can update the UI, so when our background thread wants to update the UI, we need a means to communicate between threads. Actually even your background thread can update the UI, but this is really dangerous and your app can crash!

Android provides a lot of multi threading constructs for us.

AsyncTask is by far the easiest way of multithreading in Android. When you create a new AsyncTask object the framework creates a new thread for you and provides methods to communicate with the UI. No threads, no handlers and no Executors (Because it uses these classes internally)! So why not use AsyncTask all the time? Well, because these are suited for background work that typically last for a short period of time only.

Before we look at more options that we have lets look at Handler and Looper:
When you create a new Handler it delivers messages/runnables to the thread that it was created in. This is the default implementation though. A Handler can also be created by passing in a Looper object belonging to a different thread. In this case the handler delivers messages to the the thread whose Looper was used.
And what's a Looper? It is just used to add a message loop to a Thread. And how do you add messages to the message queue? Yes, a Handler!

Ok, so other than AsyncTasks, some of our other options are:
Thread + runOnUiThread
Thread + Handler
HandlerThread.

Thread + runOnUiThread: You create a new Thread for Background work and whenever your work is done and you want to update the UI, call runOnUiThread.
doLongBackgroundWork();
runOnUiThread(new Runnable() {
                public void run() {
                    // Update the UI
                }
            });

Thread + Handler: So let's say you create a new thread to handle background work. There are 2 ways to use a Handler to communicate with the UI thread:

  • Create a Handler in the UI Thread and pass it to the new thread that we create. 
  • Within the new thread, create a Handler like: 

mHandler = new Handler(Looper.getMainLooper()) { 

So in terms of use cases, when would we use runOnUiThread vs. using a Handler? Frankly, I don't think it matters because if we look at the source code for runOnUiThread, it calls a Handler!

public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}

HandlerThread: Is basically a thread with a Looper. We can create a new object of this class and access its Looper. This Looper can then be used to create a new Handler object.

BTW, we also have an Executor class which handles a pool of threads, whereas a Handler only references a single thread.

Sometimes with all this going on, you might not know which thread you are on. To check if you are on the UI thread or some other thread you can do:
if(Looper.myLooper() == Looper.getMainLooper())
If this returns true, you are on the UI Thread.

Comments

Post a Comment

Popular posts from this blog

endmenu in different file than menu?

A binary with debug symbols with the Android NDK