精简版Handler机制
一.前言
* <p>There are two main uses for a Handler:
* (1) to schedule messages and
* runnables to be executed at some point in the future; and
* (2) to enqueue
* an action to be performed on a different thread than your own.
官方文档给了Handler机制的两个主要用处:
-
定时执行任务
-
线程间通信
二. 用到的类
Message
官方定义:
/**
*
* Defines a message containing a description and arbitrary data object that can be
* sent to a {@link Handler}. This object contains two extra int fields and an
* extra object field that allow you to not do allocations in many cases.
*
* <p class="note">While the constructor of Message is public, the best way to get
* one of these is to call {@link #obtain Message.obtain()} or one of the
* {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
* them from a pool of recycled objects.</p>
*/
简单来说Message就是信息载体,通过handler发送(post 发送的Runnable也会被封装成Message),主要成员变量:
-
what 用来区分消息类别
-
Arg1、Arg2、object 预制数据容器
-
target 绑定Handler handler在发送Message对象的时候 会把自身赋值给target,在MessageQuene做消息分发的时候,才会回调对应的Hanlder处理消息
官方也给出了获取Message的推荐方法:
Message.obtain();
Handler.obtainMessage();
而Handler.obtainMessage( )最终也是调用了
Message.obtain()
@NonNull
public final Message obtainMessage()
{
return Message.obtain(this);
}
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
Handler
Handler 是我们使用最多的类,主要用来发送消息和处理消息。
主要方法:
new Handler().postDelayed();
new Handler().post();
new Handler().sendEmptyMessage();
new Handler().sendMessage();
这几个方法组中都会调用
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
MessageQuene
/**
* Low-level class holding the list of messages to be dispatched by a
* {@link Looper}. Messages are not added directly to a MessageQueue,
* but rather through {@link Handler} objects associated with the Looper.
*
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
Message的队列,本质是一个单链表,通过和Looper关联的Handler添加Message,可以通过Looper.myqueue获取到MessageQuene。
@UnsupportedAppUsage
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);//epoll 机制
...
...
这里有个重点,当Looper通过循环去获取Message的是时候,MessageQueue的next方法会先调用nativePollOnce方法,这个本地方法
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
这里用到了epoll机制
epoll是一种IO多路转接技术,在LINUX网络编程中,经常用来做事件触发,即当有特定事件到来时,能够检测到,而不必阻塞进行监听。
当messageQueue中没有message的时候,会让线程暂时休眠,而不是通过无限循环进行监听,提高性能
Looper
在列举的几个类中,个人认为Looper是个关键,它连接了Handler和MessageQueue,是一座桥梁,是整个Handler机制的引擎。
看下官方介绍对它的定义:
/**
* Class used to run a message loop for a thread. Threads by default do
* not have a message loop associated with them; to create one, call
* {@link #prepare} in the thread that is to run the loop, and then
* {@link #loop} to have it process messages until the loop is stopped.
*
* <p>Most interaction with a message loop is through the
* {@link Handler} class.
*
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>
*/
Looper通过名称可以看出它是一个循环体,Looper通过Looper.prepare()初始化并且保存在ThreadLocal中,和线程绑定,当调用Looper.loop() 的时候,开启循环,循环中不断去MessageQueue中获取Message,并执行消息分发。
官方距离Looper的使用过程,但我们看到在UI线程中我们并没有调用Looper的对应方法,应为Android系统在创建启动的时候就帮我们完成了这一步骤:
public static void main(String[] args) {
...
...
Looper.prepareMainLooper();
...
...
Looper.loop();
}
三.工作流程
介绍完主要的类,我们把几个类的职能串联起来就是Handler机制工作流程了:
- 线程使用Handler机制,首先创建Looper对象
public 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));
}
-
Looper对象中创建MessageQueue
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
-
Looper对象开启循环
public static void loop() {
...
...
for (;;) {
...
...
-
Handler发送消息到Looper对象中的MessageQueue中,Looper对象从中不断获取Message,并通过handler的dispatchMessage分发消息。
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
发送消息时,handler会把自身赋值到Message中的target对象,这样做是为了在消息分发时各个handler能够处理需要自己处理的消息,避免混乱。
try { msg.target.dispatchMessage(msg); if (observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer != null) { observer.dispatchingThrewException(token, msg, exception); } throw exception; }
去除message对象后,调用message对象的target对象的messageDispatched分发消息。
我们知道发送消息有多中方式:
new Handler().postDelayed();
new Handler().post();
new Handler().sendEmptyMessage();
new Handler().sendMessage();
那么它们的调用顺序是怎样呢?
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这里非常清晰:
post的Runnable优先级最高
其次是handler声明的callback
最后是handler的handleMessage