Handler概述
0. Message
- UI 只能在它的创建线程中进行更新是不严谨的;实验:在主线程内创建view,在子线程更新此view 是可以的;在子线程中创建view并直接更新也是可以的;但是中间间隔一段时间后会出现问题;这个是为什么呢?(主要是 RootViewImpl 会初始化完毕)
- Message 类中可以直接设置 bundle ,但是这样的效率低,不如直接在 arg 或 obj中进行设置;
- Message 存在复用池(其实是链表),spool即当前可复用Message,next为链表下一项;Message中 的flags为复用标志 1在池中,0在使用;recycle方法中入池,初始化Message的状态,并更新链表;
Message.obtain()
为出池并更新链表; Loopre.loop
方法进行分发消息,由Handler.dispatch()
进行分发;Message 消息分发处理流程:先看Message中的callback(runnable接口)是否有设置,如果有调用Message.callback
结束。否则查看对应的handler的callback是否有设置如果有设置并且返回值为 true 则结束分发。否则继续调用 handleMessage;- Handler.postDelayed 方法中传入的Runnable 接口会被
Handler.getPostMessage
方法包装成 Message进行发送,即上述中Message.callback
1. ThreadLocal
- 每一个ThreadLocal实例保存着 每一个线程对应值,通过复写initialValue提供默认值;
- ThreadLocal中保存的值都是存放在其内部类ThreadLocalMap中(容量默认是16,必须是2的次方)当达到长度的2/3时进行重新计算长度;
- Thread中持有ThreadLocalMap实例,Thread Local存值过程:通过Thread.currentThread获得当前线程,取对应的ThreadLocalMap,如果此map存在则计算当前
ThreadLocal.threadLocalHashCode
作为key,存入Map;如果map不存在,则在上述基础上创建map并为当前的线程赋值。所以一个线程的Thread Local 只有一个,每个ThreadLocal实例为key。threadLocalHashCode的计算方式为Thread Local的静态变量中的原子整数 AtomicInteger 每个实例+1;
2. Handler消息机制
- Android 程序的入口为ActivityThread类的main方法。开启过程调用
Looper.prepareMainLoooper()
创建主线程 的Looper ,同时创建Looper的成员变量MessageQueue,并使Looper绑定当前线程,然后调用Looper.loop开启消息监听循环;在Looper.loop()
方法中是一个死循环,从Message Queue中通过MessageQueue.next()
方法获取下一个Message,在next方法中同样还是一个死循环直至获取到Message标记为使用,并通过 native代码返回;在loop中获取到Message后根据其target进行消息分发,最后通过Message.recycleUnchecked()
方法进行回收; - 消息存入队列过程:通过
Handler.sendMessage()
最后调到enqueueMessage()
进入队列;
3. Handler一些问题
- 在子线程直接创建Handler会出错是为什么?
构建 handler 必须要 Looper 对象,通过 ThreadLocal 获取对应的 Looper 对象,如果为空则会抛出错误。因此在子线程中创建 handler 需要调用Looper.prepare()
方法构建 Looper 实例。 - HandlerThread是什么?
可以看成是 handler + Thread,继承自 Thread,调用 start 方法后进行调用 Looper,在此线程中开启消息通知,并使用内部提供的 handler 进行通信。
4. 总结
Looper 中有一个 Message 队列,里面存储着等待处理的 Message;Message 中可能会指向一个Handler,这个 Handler 用来处理此Message