一直对handler机制一知半解,花了两天时间对handler从信息发送到接收,网上翻阅了一些资料结合源码重新滤了一遍,做下笔记,便于以后查阅,记忆是靠不住的。
handler机制的整个过程就是handler发送信息给looper,looper在适当的时候通过handler的dispatchMessage方法回调给handler的过程,
Handler:
android ui的改变是只能在主线程,如果子线程也能改变就会造成线程不安全。子线程要改变ui就需要线程间通信。handler是子线程刷新ui的唯一方式(runOnUiThread和view.post本质上都是handler)。Handler的构造方法需要传入looper,如果没有传默认使用当前线程的looper。Handler通过looper,获取到MessageQueue队列,在将message塞进MessageQueue里面。
Handler有5个post runnable的方法和7个send message的方法,post runnable会通过getPostMessage的方法转成send message的方法,会把runnalbe赋值给Message的callback变量(dispatchMessage会用到),最终都是调用messageQueue的enqueueMessage,在调用该方法之前,会把当前的handler赋值给message的target变量,这个很重要,这个是looper通过message找到对应handler的关键。
handler发送的部份讲完了,接下来就等着dispatchmessage被回调。dispatchMessage做的处理也很简单,判断message的callback是否为空,就是判断是否是post runnable的调用,如果不为空直接处理,message.callback.run()也就是调用runnable的run方法。如果为空,就调用handler子类实现的handleMessage方法。
Looper
一个looper对应一个线程,一个线程最多只能有一个looper。主线程默认是有创建looper,并进行loop循环的。子线程默认是没有loop的,需要通过Looper.prepare创建looper,并通过Looper.loop进行消息队列的循环处理。
所以我们来看看Looper的prepare和loop两个关键的方法做了什么,prepare方法new looper并将创建的looper set到ThreadLocal里面(这个ThreadLocal是什么,为什么这么做,我们下面在说)。这样prepare工作就完成了,prepare是必须在loop方法之前调用。
在来看看loop方法,通过ThreadLocal的get方法获取looper,prepare怎么存,我们现在就怎么取,取到looper后就取到MessageQueue,然后就死循环处理队列里面的message,message.target.dispatchMessage,通过message的target变量回调handler的dispatchMessage。这样hander到looper的循环就讲完了。
Message
数据类,用于Hander和looper的交互,数据传递
MessageQueue
message的数据队列
ThreadLocal
ThreadLocal是数据存储类,存储于线程相关的数据,但它并没有直接和Thread打交道,而是通过它的内部类ThreadLocal.value与thread类沟通,每个thread都有一个ThreadLocal.value的成员变量,value是一个存储键值对的容器,ThreadLocal把自己当成键值,looper当成value,存储到ThreadLocal.value,这样Looper就与thread相关联。 每个Looper都有一个ThreadLocal,键值唯一,Looper就和thread一一对应。
ps: 怎么保证在一个线程(线程A)定义的handler,在其他线程(线程B)中通过这个handler调用的send message,怎么能保证handerl的dispatchMessage就能在线程A中执行呢。我是这么理解的,Looper是存储在Thread里面的,就是looper是属于线程A的,MessageQueue是属于looper的,message是属于messgequeue,所以message是属于线程A的,那message调用的dispatchmessge也应该是在线程A中执行的,不知道这样理解是否有误。