Mastering Android Handler

Gaurav
MindOrks
Published in
10 min readJul 5, 2018

What is Handler, internals and Best practices. Back to Basics.

Credits: Pexels.com

Preface

If you are an Android developer, I can say with surety you have used Handler directly or indirectly. The question arises do you understand it in depth? Let’s go back to basics and learn in and out of Handler. Basic understanding of Java threads and generics is expected. For naive to experienced developers, this article aims to cover something for everyone.

What is Handler?

First thing first, Handler is not related to UI. Read last line again. Before we jump into Handler business, let us set the base.

Most of UI based operating systems are single threaded. Means, only one thread is permitted to touch User interface -> drawing on the canvas. This choice is made to keep things simple and avoid complicacy. Few attempts have been made in past to make UI multi-threaded but failed because of confusing response to users, race condition, deadlock, and a few other problems.

UI Thread

Android is a single threaded UI framework. We all know there is one UI thread also known as Main thread responsible for drawing. If you touch UI in any other thread, you meet CalledFromWrongThreadException ; Therefore some mechanism is needed to perform UI work in UI thread. Most of the developers have used Handler to accomplish that. Handler and View offers post utility:

handler.post(() -> {
// do UI stuff
});
OR
view.post(() -> {
// do UI stuff
});

Are both ways identical? For now, let’s say view.post is also using Handler inside. You will understand more by the end of this article.

What is post doing here? How does it work internally? Why is it even needed? What are the tips and tricks? Let’s begin the ride.

Thread Communication:

Suppose you have two threads, A and B. How will you facilitate communication between them? Consider classical producer-consumer example. A consumer can only consume after the producer has produced. All other times, it has to wait. The point is it is the basis for Handler.

First definition of Handler: It is the Android way of Thread communication. It is not related to UI. You use Handler to order threads to perform the desired action. Any thread can be used with Handler way with a small ceremony.

But how Handler is related to a Thread and how does we can use it to order thread to do something?

Best way to understand something is make our own hands dirty. Suppose you do not have Handler and you are writing a library to make threading easy with following requirements:

  1. A developer must be able to run any piece of code in any thread
  2. A developer must be able to run any piece of code in a thread of their choice
  3. A developer must be able to run any piece of code in a thread of their choice in any class they need (don’t worry you will understand soon)
  4. Make point 2/3 as easy as possible

Run any piece of code in any thread

If not Handler, I will give a shot using ThreadPool and Runnable/Callable. I think this should suffice and does not deserve explanation here. If you want to share a better way, feel free to leave a note OR comment.

Run any piece of code in a thread of their choice

One solution is we can have our own ThreadFactory and spawn a thread as needed. We can have BlockingQueue <Command> attached to each Thread spawned and we can post our custom Command object every-time we need to do something in that particular thread.

Let’s say we spawned a thread named NetworkThread which accepts only NetworkCommand. Consider this shitty piece of code:

Thread networkThread = new Thread(){
@Override
public void run() {
BlockingQueue<NetworkCommand> queue = new ArrayBlockingQueue<NetworkCommand>();
while(isRunning) {
NetworkCommand command = queue.take();
// execute command
}
}
};
networkThread.setName("NetworkThread");
networkThread.start();
Where,
class NetworkCommand<Runnable> extends Command{
public void execute(){ runnable.run(); }
}

Similarly, you can spawn as many Threads you need and point 2 is taken care. We can run any piece of code using our NetworkCommand which can have Runnable/Callable or any other interface.

Run any piece of code in a thread of their choice in any class they need which is readable

In point 2 solution, developers can call queue their Command from any class and they will get callback in NetworkThread. Point 3 is partially taken care as well.

There are a few small problems here:

  1. It is not readable when many Runnable are queued in callers class and it reads ugly
  2. Ugly
  3. Ugly
  4. What if you want to pass anything other than heavy Runnable, for e.g an int representing data Loaded signal
  5. How do you identify by just reading which Runnable is called in which thread? You might need to invent your own way, Annotation is one solution and comment is other. // Many devs: Sorry what is a comment?
  6. Ugly
  7. Many other issues you will encounter OR requirements you need to fulfill

How about we create 3 classes

  1. A class which takes care of Thread and Looping through Blocking Queue
  2. Generic Command class with the capability of carrying a different type of data [You create these objects and consume]
  3. A class you can attach your command to as destination [Each command has a target where the command will be received]. You send your commands to this class and it adds these commands to blocking queue under the hood. This allows the possibility of queuing commands with delay and other cool functionalities.
  4. First class loops and calls Target class (3) of command
  5. You can create multiple objects of Target class(3) and it appears they are part of Worker Thread

In a nutshell, we just discussed the architecture of Handler.

Let’s just say Android framework devs realized very early they will be using one Thread at a lot of places and they need to make spaghetti code calling everything from everywhere. They came up with a solution for Point 3 & Point 4 and architected it in Handler, Looper and Message.

Summary of Part 1

To maintain the requirement of passing work from different threads and ensuring it feels natural and easy to understand, Android framework devised this mechanism of passing messages around and used it like no tomorrow. They created a class which runs on any thread of your choice and loops infinite unless you say otherwise. Now you understand why it is called Looper. It is similar to blocking queue looping. Every message it receives has a target attached to it which handles the command, they named it Handler. Every command is called Message, I am sure the author does not remember why the name.

Simple requirement is Handler cannot be instantiated without Looper. After all, it needs that queue. If the Thread you want to use has its Looper, you can create Handler with

Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};

If you run this code in UI thread, it will execute properly and magically UI thread looper (queue) will be attached to myHandler. But if you run this in another thread, you will face error.

New developers face this issue, you might have faced as well: Can’t create handler inside thread that has not called Looper.prepare()

May of us have copied the following code:

Looper.prepare();

mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// process incoming messages here
}
};

Looper.loop();

It worked like magic but I always had some itch what the heck it is!

(Bitch about Android) I must admit, this is one of the rare scenarios when I admire Android(while most devs hate this implementation). Usually, I say Android is developed based on what Youtube and Gmail apps demand where it should be vice-versa. Handler is a really clever mechanism of thread communication they have created. They allow thread to switch task and it does not seem like heavy thread work. It appears natural(to me OR I have just accepted the reality of life). How does it happen? Let me try to shed some light.

In any thread, Handler internally calls

mLooper = Looper.myLooper();

which uses ThreadLocal [One object per Thread]

/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}

and if it does not find (which your thread does not have), you meet RuntimeException

// From handler constructormLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}

It very very simple once you grasp it.

So your normal thread does not have Looper associated with it. Simple, attach a looper using utility prepare:

// You call this public method which internally calls another preparepublic static void prepare() {
prepare(true);
}

private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}

Once prepared you can create a new Handler Object and it will not crash with Runtime exception. Following code in your run method:

          Looper.prepare();

mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// process incoming messages here
}
};

Now you attached a looper (queue) and created Handler as well. What is missing? It is like politicians promising in the political memorandum and never achieving any results. We forgot the main part, execution.

We attached the looper and assigned a Handler which can receive callbacks but we forgot to loop through the messages which is fairly simple with loop method

         Looper.prepare();

mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// process incoming messages here
}
};

Looper.loop();

Loop method says:

/**
* Run the message queue in this thread. Be sure to call
* {
@link #quit()} to end the loop.
*/
public static void loop() {
...
...
...
for (;;) {
...
...
}
...
...
}

It has an infinite loop which simply waits for messages (remember blocking queue) and calls the message target which is Handler.

You can attach as many Handlers as you want to your thread which has Looper. I leave that as an exercise for you.

HandlerThread

The above thread we saw which has looper and handler can be called HandlerThread. One day Android framework devs realized this small ceremony can be offered as Utility and they created HandlerThread (literally the name).

If you need a worker thread which should have looper attached to it, you can use this utility. It does not save you much code but it is a decent wrapper above looper API. You need to call:

HandlerThread mHandlerThread = new HandlerThread("CustomName");
mHandlerThread.start();
handler = new Handler(mHandlerThread.getLooper()) {}

And you have another worker thread ready which is capable of queuing messages and running in background aligned to Android way.

Tip

In my all apps, I have one worker thread which I create using HandlerThread. I use it everywhere UI thread can’t be used for small small tasks.
Note: All requests to this are queued as per Handler looper contract, so I choose it explicitly for tasks which can be queued.

Message

Is there anything special about Message? Android framework uses it extensively inside. However, it has a few more use cases like IPC which we will cover sometime later. Important to know in the context of this article is Message has a cached queue inside. You should not use a plain constructor.

/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}

I find it a weird API (did I just define whole Android?). if something is Public, do not write preferred way. It would have been better if they had made it non-public(IMO). Life is good when binary. When we are in May be dilemma, we never enjoy anything.

Obtain method maintains a pool and reuses objects when possible.

/**
* Return a new Message instance from the
global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {}

Tip

There is a small catch here, 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.

* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
void recycleUnchecked() {}

Once the message is recycled, it can be reused again when 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. Dare to debug? Welcome to threading world!

Solution Whenever you want to consume message with some delay(not instant), use copy:

Message copy = Message.obtain(msg);

Summary

Handler, Message, Looper all combined help you easy threading in Android. This might not be the perfect solution but one of my favorite from framework. Message is a command with 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.

Back to question:

view.post(() -> {
// do UI stuff
});
OR
handler.post(() -> {
// do UI stuff
});

So, are they identical? They are not identical but close. A minor difference is View.post will queue request if View is not attached(after it is attached, it will use UI Handler to post) and handler will immediately post to UI thread queue. So, if you want to touch a particular View, former is better approach. Using the wrong way might lead to difficult to reproduce bugs.

Handler and IPC, post message to other apps. Read Chapter 2 here.

👏 clap 👏 & share if you like it and follow me(Twitter) for the updates. Share, Comment or start a discussion. Feel free to correct mistakes.

Credits: Article Originally published here

--

--

Gaurav
MindOrks

Tech Enthusiast, Trainer & Wannapreneur, gaurav-khanna.in ( Want to happy, healthy and productive? GoodApp https://share.goodapp.in/gaurav)