最近在画各种图,所以这里贴贴图来说明一下
Handler通信的基本原理
- 为什么Handler这样用Loop搞一下,就能主子线程通信了?
创建Looper
主线程赋值mHandler变量具体实例mHander=new Handler()的过程:
- 构造Handler时候传的构造参数async为false:同步消息
- 构造Handler时候传的构造参数async为true :异步消息
- Message调用setAsynchronous=true(当Handlerasync为false时有效):异步消息
- static Handler createAsync(@NonNull Looper looper):异步消息(28)
- 上述两种消息在有 同步屏障(在下面会提到) 的时候有区别
sendMessage发送消息流程
一般不在这里唤醒Looper,除非:图中(贴代码的部分) 一开始的唤醒判断为true,并且传入消息参数的是最早的异步消息
loop.loop流程
- next()获取消息
先发一下看看用图片的效果,后面的继续补充
唤醒和挂起
同步屏障:在取消息的时候,会暂时忽略同步消息,只处理异步消息和等待异步消息插入
-
添加同步屏障流程
屏障同样是根据时间来插入到队列中适当位置,且只会挡住后面的同步消息
插入屏障不会唤醒消息队列
-
代码添加同步屏障
//获取当前线程Looper对象的消息队列 MessageQueue queue=handler.getLooper().getQueue(); //通过反射调用 Method method=MessageQueue.class.getDeclaredMethod("postSyncBarrier"); method.setAccessible(true); token= (int) method.invoke(queue);
移除同步屏障流程
- 代码移除同步屏障
//移除同步屏障 //获取当前线程Looper对象的消息队列 MessageQueue queue=handler.getLooper().getQueue(); Method method=MessageQueue.class.getDeclaredMethod("removeSyncBarrier",int.cla ss); method.setAccessible(true); method.invoke(queue,token);
移除消息
为什么建议使用obtain获取Message
- recycleUnchecked源码如下:
@UnsupportedAppUsage 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++; } } }
其他API (public)
- MessageQueue类
- 是否处理空闲状态: boolean isIdle()
- 添加空闲时处理的消息:void addIdleHandler(IdleHandler handler)
- 移除空闲时处理的消息:void removeIdleHandler(IdleHandler handler)
- 是否没有被阻塞,当前处理轮询事件中:boolean isPolling()
- 无参的的同步屏障:int postSyncBarrier()
- 移除同步屏障:removeSyncBarrier(int token)
- Handler类
- 直接跳到分发消息这一步:dispatchMessage(Message msg)
与上面的类似(上面是在当前handler处理),还有个 当前handler往主handler塞有延迟时间的处理消息:runWithScissors() - (静态方法)不通过构造方法,而是用方法构造异步消息:static Handler createAsync(Looper loop)、static Handler createAsync(Looper loop,Callback callback)
- (静态方法)获取系统主Handler没有再getMainLooper创建一个:static Handler getMain()
- (静态方法)如果参数Handler是空的,则使用主Handler:static Handler mainIfNull(Handler handler)
- 崩溃时控制台打印的字符串定义:String getTraceName(Message message)
- 获取handler绑定的Looper:Looper getLooper()
- 直接跳到分发消息这一步:dispatchMessage(Message msg)
简要提提延伸
- Message.obtain()
- Handler泄露
- 各种内置子线程的Handler实现
- IdleHandler
- 判断主线程
- 优先级链表
- 线程本地