Handler消息循环机制是Android为多线程更新UI的一套消息传输机制。
Handler的消息循环主要由四部分组成,
- Handler:处理消息的类
- Looper:是一个线程本地变量(ThreadLocal),其中封装了MessageQue队列。是一个接收消息并且保存到queue中,自身一直在循环取queue中数据的过程,具备线程安全机制,且内部只维护一个消息队列。
- 还有一些运行静止状态的回调 ,有兴趣可以看下循环取消息的地方 (这里可以在ActivityThread类中看到一些应用)
- 关于每次消息执行时间的打点的回调执行 , 有兴趣可以看下取到消息后的地方 (可以使用来检测卡顿配合帧率回调可以记录app运行性能)
- MessageQue是一个线程安全的队列,looper通过不断的循环来拿队列中的消息,如果队列是空的话则会阻断,直到有消息到来,拿到新的消息去处理。
- Message:消息内容的封装,会持有Handler的实例(target属性,此处是内存泄漏的一个地方),在消息处理的时候其实是通过target的属性来进行消息处理。
关于四者以及Thread的关系
- Handler创建需要一个Looper
public Handler() {
this(null, false);
}
public Handler(@Nullable Callback callback) {
this(callback, false);
}
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}
...
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
看最后一个我们直接new Handler()的最后会执行到的构造函数
- looper 是由Looper的类给出的静态方法,可以看到,我们是每次调用方法静态的属性会创建好,ThreadLocal线程私有存储这个可以搜资料,每个线程一个数据对象。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
/**
* 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();
}
- queue保存在looper中,queue会跟着looper一起是线程本地变量
- Handler的切换线程是依赖于Looper,Looper才是每一个线程私有,这样实现了Handler方法或者消息切换线程的基础,因为Handler携带的消息会在Looper所在的线程被执行
发送的消息如何被执行
- looper取到消息后,?
msg.target.dispatchMessage(msg);
target是啥? Message内可见是Handler; 那这个Handler是什么时候赋值的呢?看到Handler就可以看见在消息放到queue时添加的
class Message{ @UnsupportedAppUsage /*package*/ Handler target; } Handler中的方法 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内部执行
/** * Handle system messages here. */ public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
备注1:在主线程即ActivityThread中,有着app的入口方法public static void main(String[] args),里面有着一个在线程内使用Handler消息机制的实例,在进入方法的时候会调用Looper的prepareMainLooper来创建looper,之后创建Handler实例,再次调用Looper的loop方法,这样开启了looper的无线循环。
备注2:在子线程中创建的looper需要手动停止,否则会因为阻断等待而造成线程资源不会被释放。