主要的内容包括Handler的机制以及四个组成部分和源码的分析
下面的代码分析都是基于Android8.0 - Oreo的源代码
1. 消息机制简介
在应用启动时,会执行main()方法,main()会创建一个Looper对象,然后开启一个死循环,目的是不断从消息队列MessageQueue里面取出Message对象并处理。
在Android中使用消息机制,会优先想到的是Handler。Handler可以轻松的将一个任务切换到Handler所在的线程去执行。在多线程的应用场景中,可以将工作线程中需要更新UI的操作信息传递到主线程去执行,从而实现工作线程更新UI的操作,最终实现异步消息的处理。
2. Handler机制模型
消息机制主要包含Handler、Message、MessageQueue,Looper这四个类。
- Handler:消息辅助类。主要功能将
Message对象发送到MessageQueue中,同时将自己的引用赋值给Message#target(Handler.sendMessage())。也可以实现handleMessage()方法处理回调。 - Message:消息实体。需要传递的消息也可以传递数据。
- MessageQueue:消息队列。**内部实现并不是队列,而是利用单链表去实现因为在插入和删除数据有优势。**用于存储Handler发给来的消息(
Message)以及取出。内部使用单链表实现 - Looper:与线程绑定,不止局限于主线程,绑定的线程来处理
Message。不断循环执行Looper.loop(),从MessageQueue中读取Message,按分发机制将消息分发出去给目标处理(将Message发到Handler.dispatchMessage方法去处理)。
3. Handler运行流程
-
异步通信准备
假定在主线程创建Handler,则会直接在主线程中创建
Looper,MessageQueue和Handler对象。Looper和MessageQueue对象均属于其创建线程(由主线程创建则属于主线程)。创建Looper时会自动创建MessageQueue对象,创建好MessageQueue对象后,Looper自动进入循环。Handler自动绑定Looper以及MessageQueue。Looper对象的创建方法一般通过Looper.prepareMainLooper()和Looper.prepare()方法。 -
消息入队
工作线程通过
Handler发送Message到MessageQueue中。消息内容一般是UI操作,通过Handler.sendMessage(Message message)或Handler.post(Runable r)发送。加入MessageQueue一般通过MessageQueue.enqueueMessage(Message msg,long when)操作。 -
消息循环
分为消息出队和消息分发两个步骤
- 消息出队:
Looper从MessageQueue中循环取出Message - 消息分发:
Looper将取出的Message分发给创建消息的Handler
消息循环过程中,
MessageQueue为空,则线程堵塞 - 消息出队:
-
消息处理
Handler接受发过来的Message并处理。
4. Handler使用过程的注意点
-
在工作线程中创建自己的消息队列时必须要调用
Looper.prepare(),并且在一个线程中只可以调用一次,然后需要调用Looper.loop(),开启消息循环。在开发过程中基本不会调用上述方法,因为默认会调用主线程的Looper,然后一个线程中只能有一个Looper对象和一个MessageQueue。
-
要注意Handler可能引起的内存泄漏(在下面会介绍到为何会引发泄漏)。
错误的写法:
private final Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } };非静态的内部类和匿名内部类都会隐式的持有其外部类的引用,而静态内部类不会持有外部类的引用。
正确的写法:
继承
Handler时候要么放在单独的类文件中,要么直接使用静态内部类。//需要在静态内部类中调用外部类时,可以直接使用 `弱引用` 进行处理 private static final class MyHandler extends Handler{ private final WeakReference<MyActivity> mWeakReference; public MyHandler(MyActivity activity){ mWeakReference = new WeakReference<>(activity); } @Override public void handlerMessage(Message msg){ super.handlerMessage(msg); MyActivity activity = mWeakReference.get(); } } //调用方法 private MyHandler mHandler = new MyHandler(this);
5. Handler源码解析
-
创建循环器对象(
Looper)和创建消息队列对象(MessageQueue)创建Looper对象主要有两个方法:
Looper.prepareMainLooper()和Looper.prepare()创建MessageQueue对象方法:创建Looper对象时会自动创建MessageQueue
// 源码位置:../core/java/android/os/Looper.java final MessageQueue mQueue; final Thread mThread; //Looper对象创建时会自动创建一个MessageQueue对象。 private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } //为当前线程(子线程)创建一个Looper对象 需要在子线程中主动调用该方法 public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { //判断sThreadLocal是否为null,不为空则直接跑出异常 可以保证一个线程只可以调用一次prepare方法 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } //为主线程创建一个Looper对象 该方法会在主线程创建时自动调用 public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }总结:
-
创建
Looper对象时会自动创建MessageQueue对象 -
主线程的Looper对象是自动生成的,而子线程需要调用
Looper.prepare()创建Looper对象创建主线程是调用了
ActivityThread的main()方法。然后按照流程调用了
Looper.prepareMainLooper()和Looper.loop()。所以主线程不需要调用代码生成Looper对象。//源码位置: ../core/java/android/app/ActivityThread.java public static void main(String[] args) { ... Looper.prepareMainLooper(); Looper.loop(); ... } -
Handler的主要作用是(
在主线程更新UI),所以Handler主要是在主线程创建的。 -
Looper与Thread是通过
ThreadLocal关联的。由于ThreadLocal是与线程直接关联的,参考prepare()。 -
子线程创建Handler对象:无法在子线程直接调用Handler无参构造方法Handler创建时需要绑定Looper对象 。需要使用
HandlerThread。
-
-
开启Looper即消息循环
创建了
Looper和MessageQueue对象后,自动进入消息循环,使用Looper.loop()方法开始消息循环。//源码位置:../core/java/android/os/Looper.java public static void loop(){ //现获取Looper实例,保证调用loop时已有Looper,否则抛出异常 final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } //获取对应Looper实例创建的MessageQueue对象 final MessageQueue queue = me.mQueue; ... //开启消息循环-无限循环 for (;;) { //从MessageQueue取出Message对象 Message msg = queue.next(); // might block //取出消息为null,则退出循环 if (msg == null) { // No message indicates that the message queue is quitting. return; } //把Message分发给相应的target try { msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } //释放消息占据的资源 msg.recycleUnchecked(); } } -
创建Handler对象
创建Handler对象即可以进行消息的发送与处理
//源码位置:.../core/java/android/os/Handler.java //Handler默认构造方法 public Handler() { this(null, false); } public Handler(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()); } } //从当前线程的ThreadLocal获取Looper对象 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //获取当前Looper的消息队列 mQueue = mLooper.mQueue; mCallback = callback; //设置消息是否为异步处理方式 mAsynchronous = async; } public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }Handler的无参构造方法会默认关联当前线程的Looper对象和MessageQueue对象,设置callback回调方法为null,且消息处理方式为同步处理。 -
创建消息对象
Handler发送Message并且进入MessageQueue循环,创建方式分为两种
new Message()和Message.obtain()。通常使用Message.obtain()。这种方式有效避免创建重复Message对象。//创建消息对象 Message msg = Message.obtain(); msg.what = 1; msg.obj = "test"; //源码位置 .../core/java/android/os/Message.java /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}). */ //new Message 方法 public Message() { } private static final Object sPoolSync = new Object(); //维护一个Message池,用于复用Message对象 private static Message sPool; //obtain方法 直接从池内获取Message对象,避免new占用内存 public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; //直接从池中取出 return m; } } //无可复用对象,则重新new获取 return new Message(); } -
发送消息(Message)
Handler主要有以下几种发送消息的方式:
sendMessage(Message msg)sendMessageDelayed(int what, long delayMillis)post(Runnable r)postDelayed(Runnable r, long delayMillis)sendMessageAtTime(Message msg, long uptimeMillis)
最终都是会调用到
sendMessageAtTime(Message msg, long uptimeMillis)然后继续调用到enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)放入MessageQueue//源码位置:.../core/java/android/os/Handler.java //post方法 public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } public final boolean postAtTime(Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); } public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); } public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); } //利用post()方式发送消息,需要转换为Message向下传递 private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; //将runnable赋值到callback上 以便后续判断是post还是sendMessage方式发送的消息 m.callback = r; return m; } //sendMessage方法 public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } //所有的发送消息有关方法 都会调用到这个方法 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { //获取MessageQueue对象 MessageQueue queue = mQueue; //获取对象为空 抛出异常 if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } //对象不为空 调用enqueueMessage方法 return enqueueMessage(queue, msg, uptimeMillis); } //该方法为了 向MessageQueue插入Message private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { // 把当前的Handler设置为 消息标记位 即把消息派发给相对应的Handler实例 msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } //调用MessageQueue的enqueueMessage方法 return queue.enqueueMessage(msg, uptimeMillis); }//源码位置:..core/java/android/os/MessageQueue.java //内部是一个单链表有序序列,由 Message.when 作为排序依据,该值为一个相对时间。 boolean enqueueMessage(Message msg, long when) { ... synchronized (this) { //正在退出 回收Message if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; // p == null判断当前队列中是否有消息,插入消息作为队列头 // when == 0||when < p.when 队列当前处于等待状态 唤醒队列 if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. //当前队列有消息,按照消息创建时间插入到队列中 needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; //从对列头部开始遍历 for (;;) { prev = p; p = p.next; //循环到队列尾部或者出现一个when小于当前Message的when if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }总结:
- 发送消息时
Message.when表示期望该消息被分发的时间即SystemClock.uptimeMillis() + delayMillis。SystemClock.uptimeMills代表自系统开机到调用到该方法的时间差。 Message.when利用时间差来表达期望事件分发的时间,所以使用的是一个相对时间。
-
获取消息
发送了消息后,MessageQueue维护了消息队列,在Looper中通过
loop()不断获取Message。通过next()获取Message.//源码位置:..core/java/android/os/MessageQueue.java Message next(){ //该参数用于确定消息队列中是否有消息 下一个消息到来前需要等待的时长 int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } //该方法位于native层 若nextPollTimeoutMillis为-1 代表消息队列处于等待状态 阻塞操作 nativePollOnce(ptr, nextPollTimeoutMillis); ... synchronized (this) { ... Message msg = mMessages; if (msg != null) { if (now < msg.when) { // Next message is not ready. Set a timeout to wake up when it is ready. nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // Got a message. mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; //标记消息使用状态 flag |= FLAG_IN_USE msg.markInUse(); //返回一条消息 return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } //消息正在退出 if (mQuitting) { dispose(); return null; } } } } -
分发消息
分发消息到对应的Handler实例并根据传入的Message做对应的操作
//源码位置:.../core/java/android/os/Handler.java public void dispatchMessage(Message msg) { //若callback不为空,则代表使用了post(Runnable r)方式发送了消息,执行handleCallback方法 if (msg.callback != null) { handleCallback(msg); } else { //代表使用了sendMessage()方式发送了消息,调用handleMessage方法 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } //创建Handler实例时复写 自定义消息处理方法 public void handleMessage(Message msg) { } //直接回调runnable对象的run() private static void handleCallback(Message message) { message.callback.run(); }总结:
msg.target.dispatchMessage(msg)中msg.target指向的就是对应Handler实例,- 消息分发的优先级:
- Message的回调方法
message.callback.run() - Handler中Callback的回调方法
mCallback,handleMessage(msg) - Handler的默认方法
handleMessage()
- Message的回调方法
-
Message回收
上面讲到了新建Message推荐使用
obtain(),因为可以有效的复用消息,其中里面复用的就是sPool变量,它是在Message回收的时候进行赋值的。//源码位置 .../core/java/android/os/Message.java /*package*/ boolean isInUse() { return ((flags & FLAG_IN_USE) == FLAG_IN_USE); } public void recycle() { //正在使用 无法回收 if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; } recycleUnchecked(); } void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. //置为使用标记 flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; //将Message放在了列表里,缓存的对象由obtain()拿出来复用 synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } -
Looper退出
Looper.loop()内部由一个无限循环组成,默认情况下不会退出循环。需要退出就需要调用quit()或者quitSafely()。//源码位置 .../core/java/android/os/Looper.java public void quit() { mQueue.quit(false); } public void quitSafely() { mQueue.quit(true); } //源码位置 .../core/java/android/os/MessageQueue.java void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. //唤醒等待线程 nativeWake(mPtr); } } //直接移除MessageQueue中的所有消息 private void removeAllMessagesLocked() { Message p = mMessages; while (p != null) { Message n = p.next; //回收未被处理的消息 p.recycleUnchecked(); p = n; } //由于消息为null 则return 出无限循环 mMessages = null; } //直接移除未处理的消息 已经在执行的继续处理 private void removeAllFutureMessagesLocked() { final long now = SystemClock.uptimeMillis(); Message p = mMessages; if (p != null) { //还未处理的Message if (p.when > now) { removeAllMessagesLocked(); } else { Message n; for (;;) { n = p.next; if (n == null) { return; } if (n.when > now) { break; } p = n; } //不接收后续消息 p.next = null; do { p = n; n = p.next; p.recycleUnchecked(); } while (n != null); } } }