- Handler
- Activity.runOnUiThread()
- View.post(Runnable r)
Let's talk about the Handler mechanism
Handler is mainly composed of the following parts.
-
Handler
Handler is a message auxiliary class, which is mainly responsible for sending various message events to the message pool Sendmessage() and the handler that handles the corresponding message event handleMessage(). -
Message
Message is a message, which can hold any data and is equivalent to an information carrier. -
MessageQueue
MessageQueue, as its name implies, is a message queue. It inserts messages into the queue in time sequence, and the smallest timestamp will be processed first. -
Looper
Looper is responsible for reading messages from the message queue and distributing them to the corresponding Handler for processing. It is an endless loop, constantly calling messagequeue Next () reads the message. It will become blocked when there is no message distribution. Continue polling when there is a message available.
What should I pay attention to when using Handler in Android development
First of all, it is natural to create your own message queue in the worker thread. You must call Looper Prepare() and can only be called once in a thread. Of course, just creating Looper is not enough. You must also use Looper Loop() starts the message loop, otherwise it's useless to use loop.
We usually don't call it in development because the Looper of the main thread will be called by default.
In addition, there can only be one Looper object and one MessageQueue object in a thread.
The approximate standard writing is like this.
Looper.prepare(); Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { Log.i(TAG, "Defined in child threads Handler,And received a message..."); } }; Looper.loop();
Another thing that is often investigated is the possible memory leak caused by the Handler.
Possible memory leaks caused by Handler
We often write such code.
private final Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } };
When you write this, you will receive a yellow warning from the compiler.
In Android, Handler classes should be static or leaks might occur, Messages enqueued on the application thread's MessageQueue also retain their target Handler. If the Handler is an inner class, its outer class will be retained as well. To avoid leaking the outer class, declare the Handler as a static nested class with a WeakReference to its outer class
In Java, both non static inner classes and anonymous inner classes implicitly hold references to their outer classes, while static inner classes do not hold references to their outer classes.
To solve this problem, when we inherit the Handler, we either put it in a separate class file or directly use the static internal class. When we need to call external Activity in the static internal class, we can directly handle it with weak references, so we probably modify the following code.
private static final class MyHandler extends Handler{ private final WeakReference<MainActivity> mWeakReference; public MyHandler(MainActivity activity){ mWeakReference = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MainActivity activity = mWeakReference.get(); if (activity != null){ // Start writing business code } } } private MyHandler mMyHandler = new MyHandler(this);
In fact, in our actual development, internal classes may be used in more than one place. In this case, we need to try to use static internal classes and weak references to solve our possible memory leakage problem.
Have you ever used HandlerThread? What's it for?
HandlerThread is a convenient class provided by Android API. Using it, we can quickly create a Thread with a Looper. With the Looper Thread, we can generate a Handler. In essence, it is an ordinary Thread with an internal Looper.
The code for creating a Handler for the sub thread mentioned above is probably like this.
new Thread(new Runnable() { @Override public void run() { // Prepare a Looper, and the corresponding MessageQueue will also be created when the Looper is created Looper.prepare(); // Create a Handler and post a Message to the MessageQueue new Handler().post(new Runnable() { @Override public void run() { MLog.i("Handler in " + Thread.currentThread().getName()); }