Handler消息机制由四部分组成:
- Looper:
- MessageQueue:
- Handler:
- Message
结构图.pngLooper、MessageQueue、Handler、Message 之间的关系
从设计模式角度来看,Handler机制可以说是一个生产者-消费者模式:
Handler
是生产者,生产Message
,并将Message
放入MessageQueue
队列中。而Looper
是消费者,它从MessageQueue
队列中拿到Message
进行处理(消费)。
Handler消息机制的实现
-
Message类:消息的封装
成员变量 说明 target 调用enqueueMessage()方法的Handler对象实例 next MessageQueue中下一个Message对象 when 处理时期,在MessageQueue中Message对象按升序排列 ... -
Message的复用:
因为Android中消息是通过Handler机制驱动的,很多消息都需要用到Handler机制。如果每次消费完一个Message就将对象设置为null,让出内存,在生产Message时又得使用new去重新申请内存,可能会造成内存抖动问题。所以在消费完Message后,不会让出Message内存,而是将其内容置空,留下一个Message壳,在生产下一个Message时可以直接复用该Message。
-
在
Message.recycleUnchecked()
方法中,会将Message对象的所有配置都重置,只留下一个Message空壳。//消费完Message后,重置内容。 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 = UID_NONE; workSourceUid = UID_NONE; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
-
在重置完Message对象后,使用
obtain()
方法可以拿到被重置完的Message对象,并进行复用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; } } return new Message(); } //Activity中 new Handler().sendMessage(Message.obtain());
-
-
-
MessageQueue类:传送带,负责存放Message消息,存放消息方法是
enqueueMessage()
成员变量 说明 mQuitAllowed:boolean 如果消息队列可以退出,则为真。主线程中为fasle mMessages:Message 列表中第一个Message消息。后面message由next获得 mQuitting:boolean 是否正在退出标记位 ... 在
enqueueMessage()
中主要就是将要加入的message根据时间升序加入链表中,然后在需要的时候调用nativeWake()
去唤醒Looper。插入链表是按照when升序进行排序的。//MessageQueue.java boolean enqueueMessage(Message msg, long when) { //省略 synchronized (this) { //如果MessageQueue正在退出 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; }// end 如果MessageQueue正在退出 msg.markInUse(); msg.when = when; //MessageQueue中保存着第一个Message,即mMessages Message p = mMessages; //是否需要唤醒标记位 boolean needWake; //按照时间排序,与msg对比,when小的排前面 if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; } else { needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } if (needWake) { nativeWake(mPtr); } } return true; }
-
Handler类:生产(发送)消息的源头
在Handler类中,无论我们调用sendMessage()、postMessage()还是其他的方法,最终都会调用到enqueueMessage()方法上。
enqueueMessage()
方法最终走到了MessageQueue.enqueueMessage()
上Handler handler = new Handler(); handler.sendMessage(Message.obtain()); //Handler.java 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); }
-
Looper类:处理消息,主要通过
loop()
方法中的死循环获取MessageQueue中的Message主线程的Looper在应用启动时便启动且开始了死循环,它是在
ActivityThread.main()
方法中初始化并启动的。Looper的初始化调用的是Looper.prepareMainLooper()
//ActivityThread.java public static void main(String[] args) { //省略 Looper.prepareMainLooper();//<<<<看这里 //省略 }
-
在
Looper.prepareMainLooper()
方法中,调用preapre(false)对Looper进行初始化。其中参数false
最终会被设置到MessageQueue中的成员变量mQuitAllowed
中,表示该线程对应的MessageQueue不能调用quit()
方法。//Looper.java public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } void quit(boolean safe) { //如果 mQuitAllowed == fasle ,即不允许退出。则调用该方法会抛出异常 if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } //省略 }
-
在
prepare()
中,会去判断当前线程是否已经存在一个Looper对象实例,如果没有则通过new Looper()
新建一个Looper对象实例并保存到sThreadLocal中。如果该线程原本就有了一个Looper对象实例,则抛出异常。因此一个线程只能有一个Looper对象实例。//Looper.java 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的唯一?
答:通过在prepare()方法中对当前线程Looper对象实例是否唯一进行检测,且新建好的Looper会存储在静态常量sThreadLocal中,两部分来保证线程中Looper实例的唯一。
-
在
new Looper()
中,会一并初始化MessageQueue对象实例。也就是说每个Looper会持有一个MessageQueue对象,且因为Looper在线程中的唯一性,MessageQueue在线程中也是唯一的。private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
-
初始化完Looper后,调用
loop()
方法进行死循环获取MessageQueue中的message进行操作//ActivityThread.java public static void main(String[] args) { //省略 Looper.prepareMainLooper(); //省略 ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } //省略 Looper.loop();//<<<<<<<<<<<<<<<<<看这里 throw new RuntimeException("Main thread loop unexpectedly exited"); }
-
在
loop()
中-
拿到当前线程中的MessageQueue,并且调用了
MessageQueue.next()
,在next()
中继续用死循环获取Message,如果下一个Message处理的时机还没到,会进行阻塞休眠。Message next() { //mPtr 类似线程的id的东西,在休眠和唤醒时有用。在native层初始化 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(); } //使用native的方法休眠,时长 == nextPollTimeoutMillis nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; //省略 if (msg != null) { //通过when判断下一个Message到时间处理没 if (now < msg.when) { //下一个Message还没有准备好。设置一个超时以在它准备好时唤醒。 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { //下一个Message到时间处理了 mBlocked = false; if (prevMsg != null) {//这个跟异步Message有关 prevMsg.next = msg.next; } else {//一般的同步Message //将第二个Message设置给mMessages, mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg;//<<<<<<<<<< 正常情况下返回 } } else { // 没有消息,设置 -1 ,将无限期休眠。 //在下一个循环中调用 nativePollOnce()时休眠 nextPollTimeoutMillis = -1; } //调用quit()时,mQuitting==true。 //主线程不能调用 if (mQuitting) { dispose(); return null;//<<<<<<<<<<< 子线程调用quit()后,会返回null } //省略 } }
-
拿到要处理的Message后,判空,如果为空,则退出Loop循环。非空则调用handler中的
dispatchMessage()
方法进行分发,实现线程间通信。public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; //省略 for (;;) { Message msg = queue.next(); // might block //判空,结束loop死循环 if (msg == null) { return; } //省略 try { //msg.target == handler 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; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag != 0) { Trace.traceEnd(traceTag); } } //省略 //Message清空数据。复用机制 msg.recycleUnchecked(); } }
-
-
网友评论