original source : https://blog.mindorks.com/android-core-looper-handler-and-handlerthread-bd54d69fe91a
참고자료 : https://stackoverflow.com/questions/12877944/what-is-the-relationship-between-looper-handler-and-messagequeue-in-android
A Looper is a message handling loop: it reads and processes items from a MessageQueue. The Looper class is usually used in conjunction with a HandlerThread (a subclass of Thread).
A Handler is a utility class that facilitates interacting with a Looper—mainly by posting messages and Runnable objects to the thread's MessageQueue. When a Handler is created, it is bound to a specific Looper (and associated thread and message queue).
In typical usage, you create and start a HandlerThread, then create a Handler object (or objects) by which other threads can interact with the HandlerThread instance. The Handler must be created while running on the HandlerThread, although once created there is no restriction on what threads can use the Handler's scheduling methods (post(Runnable), etc.)
The main thread (a.k.a. UI thread) in an Android application is set up as a handler thread before your application instance is created.
Aside from the class docs, there's a nice discussion of all of this here.
It's widely known that it's illegal to update UI components directly from threads other than main thread in android. This android document (Handling Expensive Operations in the UI Thread) suggests the steps to follow if we need to start a separate thread to do some expensive work and update UI after it's done. The idea is to create a Handler object associated with main thread, and post a Runnable to it at appropriate time. This Runnable will be invoked on the main thread. This mechanism is implemented with Looper and Handler classes.
The Looper class maintains a MessageQueue, which contains a list messages. An important character of Looper is that it's associated with the thread within which the Looper is created. This association is kept forever and can't be broken nor changed. Also note that a thread can't be associated with more than one Looper. In order to guarantee this association, Looper is stored in thread-local storage, and it can't be created via its constructor directly. The only way to create it is to call prepare static method on Looper. prepare method first examines ThreadLocal of current thread to make sure that there isn't already a Looper associated with the thread. After the examination, a new Looper is created and saved in ThreadLocal. Having prepared the Looper, we can call loop method on it to check for new messages and have Handler to deal with them.
As the name indicates, the Handler class is mainly responsible for handling (adding, removing, dispatching) messages of current thread's MessageQueue. A Handler instance is also bound to a thread. The binding between Handler and Thread is achieved via Looper and MessageQueue. A Handler is always bound to a Looper, and subsequently bound to the thread associated with the Looper. Unlike Looper, multiple Handler instances can be bound to the same thread. Whenever we call post or any methods alike on the Handler, a new message is added to the associated MessageQueue. The target field of the message is set to current Handler instance. When the Looper received this message, it invokes dispatchMessage on message's target field, so that the message routes back to to the Handler instance to be handled, but on the correct thread. The relationships between Looper, Handler and MessageQueue is shown below:
Let's start with the Looper. You can understand the relationship between Looper, Handler and MessageQueue more easily when you understand what Looper is. Also you can better understand what Looper is in the context of GUI framework. Looper is made to do 2 things.
1) Looper transforms a normal thread, which terminates when its run() method returns, into something that runs continuously until Android app is running, which is needed in GUI framework (Technically, it still terminates when run() method returns. But let me clarify what I mean, below).
2) Looper provides a queue where jobs to be done are enqueued, which is also needed in GUI framework.
As you may know, when an application is launched, the system creates a thread of execution for the application, called “main”, and Android applications normally run entirely on a single thread by default the “main thread”. But main thread is not some secret, special thread. It's just a normal thread that you can also create with new Thread() code, which means it terminates when its run() method returns! Think of below example.
This Article covers Android Looper, Handler, and HandlerThread. These are among the building blocks of Android OS.
In my own experience, I have used them in a very limited context until recently. My use case involved sending tasks to the main/ui thread, primarily to update the UI from any other thread. The other aspects of the multi-threaded operation were handled through alternate ways like ThreadPoolExecutor, IntentService, and AsyncTask.
MultiThreading and task running are old subjects. Java itself has java.util.concurrent package and Fork/Join framework to facilitate it. Several libraries have been written to streamline asynchronous operations. RxJava is the most popular library today for reactive programming and designing an asynchronous application.
So, why am I writing about the old school?
Looper, Handler, and HandlerThread are the Android’s way of solving the problems of asynchronous programming. They are not old school, but a neat structure on which a complex android framework is built.
For new developers, it’s highly recommended to understand the principles behind them and experienced one’s should revisit this topic to recollect the minor details.
The main thread in Android is built with a Looper and Handlers. So, the understanding of it is essential to create an unblocked responsive UI.
The developers writing libraries cannot afford to use third party libraries because of the library size. So, for them, the best option is to utilize the existing available resource. Writing own solution for it may not always get that level of efficiency and optimization.
The same argument can also be made for companies/individuals shipping out SDKs. The clients can have varied implementations, but all of them will share the common android framework APIs.
Understanding them fully will enhance the capacity to follow the Android SDK and package classes in general.
Let’s start the exploration/revision with a questionnaire.
I expect the reader to have the basic understanding of java threads. If you need, then get a quick overview of java Thread and Runnable.
What is the problem with java thread?
Java threads are one-time use only and die after executing its run method.
The Thread is a double edged sword. We can speed up the execution by distributing the tasks among threads of execution, but can also slow it down when threads are in excess. Thread creation in itself is an overhead. So, the best option is to have an optimum number of threads and reuse them for tasks execution.
Model for thread reusability:
The thread is kept alive, in a loop via it’s run() method.
The task is executed serially by that thread and is maintained in a queue (MessageQueue).
The thread must be terminated when done.
What is the Android’s way of doing it?
The above model is implemented in the Android via Looper, Handler, and HandlerThread. The System can be visualized to be a vehicle as in the article’s cover.
MessageQueue is a queue that has tasks called messages which should be processed.
Handler enqueues task in the MessageQueue using Looper and also executes them when the task comes out of the MessageQueue.
Looper is a worker that keeps a thread alive, loops through MessageQueue and sends messages to the corresponding handler to process.
Finally Thread gets terminated by calling Looper’s quit() method.
One thread can have only one unique Looper and can have many unique Handlers associated with it.
Creating Looper and MessageQueue for a Thread:
A thread gets a Looper and MessageQueue by calling Looper.prepare() after its running. Looper.prepare() identifies the calling thread, creates a Looperand MessageQueue object and associate the thread with them in ThreadLocal storage class. Looper.loop() must be called to start the associated looper. Similarly, the looper must be terminated explicitly through looper.quit().
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
// this will run in non-ui/background thread
}
};
Looper.loop();
}
}
Creating Handler for a Thread:
A Handler gets implicitly associated with the thread that instantiates it via thread’s Looper, but we can explicitly tie it to a thread by passing the thread’s looper in the constructor of the Handler.
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// process incoming messages here
// this will run in the thread, which instantiates it
}
};
Sending messages to the MessageQueue via Handler can be done by two modes:
Message: It is a class that defines various useful methods to deal with message data. To send an object we set the obj variable.
Message msg = new Message();
msg.obj = "Ali send message";
handler.sendMessage(msg);
Detailed overview of Message class can be found here: https://developer.android.com/reference/android/os/Message.html
2. Runnable: A runnable can also be posted in the MessageQueue. Ex: posting and running a task in the main thread.
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// this will run in the main thread
}
});
In the above example, we create a Handler and provide Looper associated with the main thread. This associate this handler to the main thread. When we post the Runnable, it gets queued in the main thread’s MessageQueue and then executed in the main thread.
Handler is capable of message manipulation in a wide variety of ways, which can found here: https://developer.android.com/reference/android/os/Handler.html
Creating an own thread and providing Lopper and MessageQueue is not the right way to deal with the problem. So, Android has provided HandlerThread (subclass of Thread) to streamline the process. Internally it does the same things that we have done but in a robust way. So, always use HandlerThread.
One of the ways to create the HandlerThread is to subclass it and most of the time you will be using this method.
private class MyHandlerThread extends HandlerThread {
Handler handler;
public MyHandlerThread(String name) {
super(name);
}
@Override
protected void onLooperPrepared() {
handler = new Handler(getLooper()) {
@Override
public void handleMessage(Message msg) {
// process incoming messages here
// this will run in non-ui/background thread
}
};
}
}
Note: We have instantiated the Handler when the onLooperPrepared() is called. So, that Handler can be associated with that Looper.
Looper is only prepared after HandlerThread’s start() is called i.e. after the thread is running.
A Handler can be associated with a HandlerThread, only after it’s Looper is prepared.
Other way to create the HandlerThread:
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
Note: HandlerThread needs to call myHandlerThread.quit() to free the resources and stop the execution of the thread.
I would suggest practicing the above codes, so you can grasp their little details.
I have created an example project for Post Office simulation. Post Office is built upon HandlerThread and Clients communicate with the help of the Post Office. A Simulator class creates few Client Bots and delegate their communication to the MainActivity, which renders it in a live feed.
The link to this Example:
MindorksOpenSource/post-office-simulator-looper-example
post-office-simulator-looper-example - This Android project simulates a Post Office using HandlerThreadgithub.com
Thanks for reading this article. Be sure to click ❤ below to recommend this article if you found it helpful. It would let others get this article in search and spread the knowledge.
For more about programming, follow me and Mindorks, so you’ll get notified when we write new posts.
Check out all the Mindorks best articles here.