参考 http://www.jianshu.com/p/ac50ba6ba3a2
http://www.jianshu.com/p/aa6b6152217d
几个要点
消息其中包括:
我们自己的操作消息(客户端的 Handler)
系统的操作消息(系统 Handler):比如启动 Activity 等四大组件(例如 突然来电话的时候跳转到电话界面)
线程不安全问题归根结底主要涉及到变量的多线程访问问题,例如变量的临界问题、值错误、并发问题等
1 系统的handler类名为大写的H (继承Handler)
2 为ActivityThread 的成员变量,在 new ActivityThread 的时候,系统的 Handler 就初始
3 在 main 方法里面,然后创建了 Looper,然后开启消息循环。之所以我们的APP能够一直运行着,就是因为 Looper.loop() 里面是一个死循环:
public static void loop() {
for(;;) { }
}
4 在非主线程里面我们也可以搞一个 Handler,但是需要我们主动去为当前的子线程绑定一个 Looper,并且启动消息循环。
5 post方法(封装了带Runnable的Message) 最终都是调用sendMessageAtTime方法,把消息放到消息队列里面:
6 消息并不是一直在队列的尾部添加的,而是可以指定时间,如果是立马需要执行的消息,就会插到队列的头部,就会立马处理,如此类推。
7 ThreadLocal 是JDK提供的一个解决线程不安全的类,线程不安全问题归根结底主要涉及到变量的多线程访问问题,例如变量的临界问题、值错误、并发问题等。这里利用ThreadLocal 绑定了 Looper 以及线程,就可以避免其他线程去访问当前线程的 Looper 了。
8 Looper 与线程的关联是通过 ThreadLocal 来进行的
9 MessageQueue 是Looper对象的成员变量 (消息队列是通过链表实现 指向下一个结点)
Looper与当前线程绑定
调用prepare(prepareMainLooper())方法来关联线程和Looper //sThreadLocal.set(newLooper(quitAllowed));
Looper的成员变量sThreadLocal
static final ThreadLocal sThreadLocal =newThreadLocal();
在prepare方法中new了一个Looper并且设置到sThreadLocal里面sThreadLocal.set(newLooper(quitAllowed));
消息池的概念
1 Message Pool消息池的概念——重复利用Message (利用享元模式去循环利用)
2 通过obtain方法取出一条消息的时候,如果发现当前的消息池不为空,那就直接重复利用Message(已经被创建过和handle过的);如果为空就重新 new 一个消息。这就是一种享元设计模式的概念
3 消息的去取出并不是直接就从队列的头部取出的,而是根据了消息的when时间参数有关的,因为我们可以发送延时消息、也可以发送一个指定时间点的消息
迭代消息过程
1 首先拿到Looper对象(me),如果当前的线程没有Looper,那么就会抛出异常,这就是为什么在子线程里面创建Handler如果不手动创建和启动Looper会报错的原因。
2 Looper的成员变量MessageQueue,在MessageQueue里面不断地去取消息
for(;;) {
Message msg = queue.next();// might block
if(msg ==null) {
// No message indicates that the message queue is quitting.
return;
}
//处理消息
try{
msg.target.dispatchMessage(msg);
}
finally{ }
}
msg.recycleUnchecked();//回收消息}
Handler、Looper是怎么关联
在初始化Handler类中
public Handler(Callback callback, booleanasync){
mLooper = Looper.myLooper();//见下文备注 第二块核心代码
//如果当前线程(子线程)没有Looper,就需要我们程序要去手动prepare以及启动loop方法了
//子线程里面默认没有Looper循环器
if(mLooper ==null) {
thrownewRuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous =async;
}
第二块核心代码
public static @Nullable Looper myLooper(){
returns ThreadLocal.get();//返回与当前线程绑定的Looper
}