1.Handler的诞生 由于Android采用的是单线程模式,开发者无法在子线程中更新 UI,因此在Android开发中,经常会在子线程中进行一些操作,当操作完成之后,将结果发送到主线程进行显示。探索其背后的模式:子线程、Handler和主线程三者组成了生产者和消费者模式。子线程负责生产数据,主线程负责消费数据,而Handler负责将数据从子线程抛到主线程中 。详细见下图
2.Handler相关的类
Hanlder:发送和接收消息
Looper:用于轮询消息队列,一个线程只能有一个Looper
Message: 消息实体
MessageQueue: 消息队列用于存储消息和管理消息。
2.1 Looper的创建
创建Looper的方法是调用Looper.prepare() 方法或者Looper.prepareMainLooper()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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)); } @Deprecated public static void prepareMainLooper () { prepare(false ); synchronized (Looper.class) { if (sMainLooper != null ) { throw new IllegalStateException("The main Looper has already been prepared." ); } sMainLooper = myLooper(); } }
2.2 创建MessageQueue以及与Looper和当前线程绑定 1 2 3 4 5 6 7 8 9 10 private Looper (boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }
2.3 Looper.loop()方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public static void loop () { final Looper me = myLooper(); if (me == null ) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread." ); } ...... me.mInLoop = true ; final MessageQueue queue = me.mQueue; ...... for (;;) { Message msg = queue.next(); if (msg == null ) { return ; } ...... try { msg.target.dispatchMessage(msg); ...... msg.recycleUnchecked(); } }
2.4 Handler的创建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Handler handler = new Handler(){ @Override public void handleMessage (Message msg) { super .handleMessage(msg); } }; public Handler (@NonNull Looper looper) { this (looper, null , false ); } public Handler (@NonNull Looper looper, @Nullable Callback callback) { this (looper, callback, false ); }
2.5 Message的创建 可以直接new Message()但是不建议这么使用,因为如果有大量的new Message()然后用完了就被回收,这样会导致内存抖动。推荐的方式是使用obtain()系列方法。Message使用了享元模式,内部维护了一个对象池(最大50个),管理者对象的创建和销毁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static Message obtain () { synchronized (sPoolSync) { if (sPool != null ) { Message m = sPool; sPool = m.next; m.next = null ; m.flags = 0 ; sPoolSize--; return m; } } return new Message(); } public static Message obtain (Handler h) public static Message obtain (Handler h, Runnable callback) public static Message obtain (Handler h, int what)
2.6 Message和Handhler绑定
方式1:通过上面创建Message时绑定
方式2:在发送消息的到时候绑定(代码如下)
1 2 3 4 5 6 private boolean enqueueMessage (@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this ; ...... return queue.enqueueMessage(msg, uptimeMillis); }
2.7 Handler发送消息 如下图调用关系,Handler发送消息的重载方法很多,但是主要只有2种。 sendMessage(Message) sendMessage方法通过一系列重载方法的调用,sendMessage调用sendMessageDelayed,继续调用sendMessageAtTime,继续调用sendMessageAtTime,继续调用enqueueMessage,继续调用MessageQueue的enqueueMessage方法,将消息保存在消息队列中。
2.8 Handler消费消息 当Looper取出,交给Handler的dispatchMessage进行处理
我们可以看到在dispatchMessage方法中,message中callback是一个Runnable对象,如果callback不为空,则直接调用callback的run方法,否则判断mCallback是否为空,mCallback在Handler构造方法中初始化,在主线程通直接通过无参的构造方法new出来的为null,所以会直接执行后面的handleMessage()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public void dispatchMessage (@NonNull Message msg) { if (msg.callback != null ) { handleCallback(msg); } else { if (mCallback != null ) { if (mCallback.handleMessage(msg)) { return ; } } handleMessage(msg); } }
3.难点问题 3.1 消息加入和取出如何保证线程安全 MessageQueue在消息入队的时候和取消息的时候都会对队列加锁,保证要么入队消息,要么出队消息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 boolean enqueueMessage (Message msg, long when) { if (msg.target == null ) { throw new IllegalArgumentException("Message must have a target." ); } synchronized (this ) { ...... } Message next () { ..... for (;;) { ...... synchronized (this ) { ...... }
3.2 消息机制之同步屏障 通过上面分析,通常情况下Handler抛的消息会按照时间排序,然后Looper从头部开始一个一个取消息执行。但是有个需求是在一个小的时间范围内,handler抛的消息需要优先执行,那我们应该如何处理呢?例如UI需要立马重绘,而且需要优先处理这个消息,那就要用到消息同步屏障。
MessageQueue.postSyncBarrier() //开启同步屏障
MessageQueue.removeSyncBarrier() //移除同步屏障
Message.setAsynchronous(true) //设置为异步消息
3.2.1 开启同步屏障 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public int postSyncBarrier () { return postSyncBarrier(SystemClock.uptimeMillis()); } private int postSyncBarrier (long when) { synchronized (this ) { final int token = mNextBarrierToken++; final Message msg = Message.obtain(); msg.markInUse(); msg.when = when; msg.arg1 = token; Message prev = null ; Message p = mMessages; if (when != 0 ) { while (p != null && p.when <= when) { prev = p; p = p.next; } } if (prev != null ) { msg.next = p; prev.next = msg; } else { msg.next = p; mMessages = msg; } return token; } }
此处开启同步屏障之后,从消息池获取的Message中target==null。
3.2.2 处理异步消息 从下面可以看出,当消息队列开启同步屏障的时候(即标识为msg.target == null
),消息机制在处理消息的时候,优先处理异步消息。这样,同步屏障就起到了一种过滤和优先级的作用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 Message next () { ..... for (;;) { if (nextPollTimeoutMillis != 0 ) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this ) { final long now = SystemClock.uptimeMillis(); Message prevMsg = null ; Message msg = mMessages; if (msg != null && msg.target == null ) { do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null ) { } ..... }
如果开启了同步屏障,在返回的msg中会被重新赋值,所以如果开启了同步屏障,MessageQueue会遍历队列中是否有时间到了的异步消息,如果有就重新给msg赋值让他返回出去给handler处理。
示意图如下:
3.2.3 同步屏障的使用场景 在 View 更新时,draw、requestLayout、invalidate 等很多地方都调用ViewRootImpl#scheduleTraversals()
,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void scheduleTraversals () { if (!mTraversalScheduled) { mTraversalScheduled = true ; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null ); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private void postCallbackDelayedInternal (int callbackType, Object action, Object token, long delayMillis) { if (DEBUG_FRAMES) { Log.d(TAG, "PostCallback: type=" + callbackType + ", action=" + action + ", token=" + token + ", delayMillis=" + delayMillis); } synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); if (dueTime <= now) { scheduleFrameLocked(now); } else { Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); msg.arg1 = callbackType; msg.setAsynchronous(true ); mHandler.sendMessageAtTime(msg, dueTime); } } }
3.3 同步执行消息 3.3.1 runWithScissors()分析 我们从前面的分析可以看出生产者-消费者模式其实是异步的执行操作。生产者生产好了商品向容器里面放,消费者只管从容器取就行,但是有这么一个场景,就是我生产的东西需要消费了才能继续生产下去,那么就需要考虑同步执行消息了。(可能举例不恰当)但是在framework中,WindowManagerService初始化的时候,就会出现这样的情况,WindowManagerService的初始化是放在显示子线程 完成的,但是使用多线程来初始化服务虽然加快了初始化速度,但是也会出现一种情况就是某个服务没有初始化结束,导致其他服务运行异常的情况。因此系统提供了Handler.runWithScissors()这个方法来实现同步执行消息。如果任务没有执行结束,该线程不能执行其他的任务。下面我们来分析一下这个方法:
1 2 3 4 5 6 public final boolean runWithScissors (@NonNull Runnable r, long timeout) { ...... BlockingRunnable br = new BlockingRunnable(r); return br.postAndWait(this , timeout); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public boolean postAndWait (Handler handler, long timeout) { if (!handler.post(this )) { return false ; } synchronized (this ) { if (timeout > 0 ) { final long expirationTime = SystemClock.uptimeMillis() + timeout; while (!mDone) { long delay = expirationTime - SystemClock.uptimeMillis(); if (delay <= 0 ) { return false ; } try { wait(delay); } catch (InterruptedException ex) { } } } else { while (!mDone) { try { wait(); } catch (InterruptedException ex) { } } } } return true ; }
1 2 3 4 5 6 7 8 9 10 11 public void run () { try { mTask.run(); } finally { synchronized (this ) { mDone = true ; notifyAll(); } } }
3.3.2 runWithScissors()使用场景 1 2 3 4 5 6 7 8 public static WindowManagerService main (final Context context, final InputManagerService im,final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy, ActivityTaskManagerService atm, Supplier<SurfaceControl.Transaction> transactionFactory,Supplier<Surface> surfaceFactory, Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) { DisplayThread.getHandler().runWithScissors(() -> sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,atm, transactionFactory, surfaceFactory, surfaceControlFactory), 0 ); return sInstance; }
参考文章:
同步屏障