How to Use Thread, Looper and Handler in Android

About Looper

Looper is actually a class that can run on any thread and loops infinitely. It’s similar to blocking queue looping. A looper is just like a pump, it’s a dead loop, which is used to keep listening if there is a message in messageQueue. The looper is trying to get Message or Runnable from MessageQueue.

Take the UI thread for example. The UI thread is not safe, so if we try to make some UI action on another thread it would result in a crash.

To solve the issue, we need to use handler, create a Message object, use handler to sendMessage in thread, and handleMessage() in UI thread to get it.

In Android, except for the UI thread, a normal thread would not have a looper automatically. So, if we want to build a communication between the sub-thread and UI thread, we need to do the following.

Step 1: Check if this thread already has looper or not, then use Looper.prepare(). Since every thread can only have at most one looper, so before we user Looper.prepared(), we need to check if it already has one or not.

  • How to check: Looper.myLooper(), if this thread has no looper it will return null.

Notice: call Looper.myLooper() in the constructor Thread class we can only get Main thread Looper, because at that time the new thread is not constructed yet.

Step 2: Use handler, create a Message object, use handler to sendMessage in thread, and handleMessage() in UI thread to get it.

Step 3: Use Looper.loop(), Looper.loop(). This allows the loop to begin work by getting message from messageQueue. The code after Looper.loop() would never be called unless we called get Loop().quit().

Handler & Message

It’s an Android way of thread communication. It is not only related to UI. Every message the looper receives has a target attached to it which handles the command, the message is called handler. Every command is called Message.

To make it more straight-forward — remember I mentioned Looper is like a dead loop “pump”? Handler can be treated as an interface of a looper, exposed some methods like: sendMessage() and post().

Just like I said, Message is a command for each message(Handler). But here are some very interesting attributes for Message objects.

About Message Object

Each Message object has a limited life. Once you receive it in your Handler and execution returns, from there Looper will mark message unused and recycle.

Once the message is recycled, it can be reused again next time you call Obtain. So if you cache your message and do some long running task before you process your message, there is a possibility that it is recycled and data is cleared.

Because of those attributes we cannot use a plain constructor for message. What we should do is whenever you want to consume message with some delay(not instant), use copy:

Message copy = Message.obtain(msg);

Message is a command for data which recycles itself. Handler is the place where you handle messages and take action. Looper simply is an infinite loop which delivers messages to Handlers. You can attach multiple Handlers to a Looper and there is one looper per thread. You can either call Looper.prepare() or use HandlerThread utility. Main thread initializes its Handler as soon it starts.

Tips for handler.poset():

There are two situation for Android to use this method. One for using it in MainThread and then for using it in sub-Thread.

For the mainThread:

new Handler().post(new Runnable() {
@Override
public void run() {
mTest.setText("post");//update ui
}
});

Actually this is still running in the main thread, it is equally to call sendMessage() in the main thread.

For different thread:

Handler handler;
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
handler.post(new Runnable() {
@Override
public void run() {
mTest.setText("post");//更新UI
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();

Actually the post here is the same as the bunch of code below:

private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
mTest.setText("handleMessage");//update ui
break;
}
}
};

Handler Memory Leak Problem

If we use a Handler in an Activity, the handler will have the Implicit reference for this activity. So if we make some time consuming, work by handler, the activity the handler uses cannot be recycled. A way to solve the issue is to use WeakReference instead.

Example:

static class MyHandler extends Handler {

WeakReference<Activity > mActivityReference;
MyHandler(Activity activity) {
mActivityReference= new WeakReference<Activity>(activity);
}

@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
if (activity != null) {
mImageView.setImageBitmap(mBitmap);
}
}
}

As ever, QuarkWorks is available to help with any software application project — web, mobile, and more! If you are interested in our services you can check out our website. We would love to answer any questions you have! Just reach out to us on our Twitter, Facebook, or LinkedIn.