消息机制解析
2017-10-11 本文已影响0人
刘佳阔
先上uml图
handler.png- 消息推送机制的主要角色: Handler 发送和处理消息的类.Message发送的消息对象.MessageQuene 消息队列,虽然叫消息队列,其实是单链表的数据结构,用来存储消息的类.Lopper,消息循环,不断的把消息从消息队列中拿出,交给Handler去处理.
- Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,可以分发Message对象和Runnable对象到主线程中.
- 先看ThreadLocal类.ThreadLocal是一个线程内部的数据存储类.他可以在指定的线程中存数数据,然后在指定的线程得到改数据.当某些数据是以线程为作用域并且不同线程有不同的数据副本时,可以考虑使用ThreadLocal.
1. ThreadLocal 的set.get
public T get() {
Thread t = Thread.currentThread(); //得到当前线程
ThreadLocalMap map = getMap(t);
//ThreadLocalMap 是ThreadLocal的内部类.而每个Thread内部包含一个 ThreadLocal.ThreadLocalMap的变量,名字
为threadLocals,getMap(t)返回线程的threadLocals.
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
//map中有一个Entry[] 数组, Entry 就是当前线程保存的数据bean,
table 通过ThreadLocal的hash值经过运算得到 当前线程的Entry 在table中的索引,
然后通过索引找到Entry 返回给外边.
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread(); //同样是找到该线程,
ThreadLocalMap map = getMap(t); //得到线程的 ThreadLocalMap
if (map != null)
map.set(this, value); //把要保存在线程中的值保存在map中的 table中.若table对这个ThreadLocal原来
有数据就更新数据,没有数据就添加数据
else
createMap(t, value); //新建一个ThreadLocalMap,并赋值给Tread的threadLocals,同时新建table数组,把value保存起来.
}
可以看到,最终Threal保存数据,靠的是操作ThradLocalMap中的table数组.
2. MessageQuene 的enqueueMessage和 next
首先看一下Message 的主要参数
Handler target.//发送Message的那个handler.
Runnable callback . //handler.post(Runnable ) 方式发送消息时传递的参数.
Message next; //当前msg执行完成后接下来要执行的msg的引用
long when; //消息需设置的延时时间,在入栈时会加入当前时间转化为消息需要执行的绝对时间.
MessageQuene 的消息入队操作
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) { //msg是否正在被使用.
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) { //表示线程需要退出了.消息加入失败
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse(); //把msg标记为使用状态,同上文照应.
msg.when = when; //when表示消息需要执行的绝对时间
Message p = mMessages; // mMessages表示队列中最先要执行的msg
boolean needWake;
//新增的msg比mMessage还要先执行,所以放在链表的头部
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else { //否则的话.就从mMessge 向后遍历,比较Message的when,将新增的msg插入到合适的位置
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next //把msg插入到p前边
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
接下来看next
//返回一个msg出去.有可能是阻塞式的,因为他有一个循环一直返回msg
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) { //如果looper退出,就返回null
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) { //开始执行消息循环
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();//得到当前时间
Message prevMsg = null; //相当于头结点
Message msg = mMessages; //即将要执行的msg //相当于尾节点
if (msg != null && msg.target == null) { //先排除掉同步的msg
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) { //到这里时.剩下了异步的msg
if (now < msg.when) { //标识msg的执行时间还没到. 就生成一个睡眠时间 nextPollTimeoutMillis
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null; //msg 就是即将要处理的消息把他从链表中移除
if (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) { //如果要退出的话.就结束msg队列的遍历 在 quite() 方法中赋值true
dispose();
return null;
}
//这里是对闲置handler的处理. 忽略------------------
}
}
最后就清楚了,MessageQuene的next方法会阻塞,等到有msg到了且msg的执行时间到达,就把msg从链表中移除.返回出去.只有在返回了msg消息或者MessageQuene.quit被调用的时候才会退出循环.
3.Looper 循环器.不断从MessageQuene中取出消息,交给Handler处理.
1.构造函数和常量.
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //在不同线程保存Looper的ThreadLocal.
private static Looper sMainLooper;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed); //直接创建一个MessageQueue 形参表示是否运行退出
mThread = Thread.currentThread(); //拿到当前线程
}
2. //Looper 通过prepare 方法在线程中创建Lopper,
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));
}
3. UI线程也是有Looper的,Looper 为主线程提供了 如下两个方法,本质也是通过prepare来创建Looper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
//拿到对应线程中的Looper方法
public static Looper myLooper() {
return sThreadLocal.get();
}
4.Looper 最主要的方法是loop(),loop会不断从MessageQuene中拿消息,然后交给handler处理
public static void loop() {
final Looper me = myLooper(); //得到当前线程的Looper对象
if (me == null) { //需要在线程中先调用prepare 生成Looper 才能开启循环
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //拿到对应的消息队列
//忽略--------
for (;;) { //阻塞的循环
Message msg = queue.next(); // 当MessageQueue的quite被调用,nxet就会返回null,然后looper也就终止循环了,此方法会阻塞
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//忽略--------------
//target 就是当初发送msg的handler,到这里消息就交给了handler来处理
msg.target.dispatchMessage(msg);
//忽略-------
msg.recycleUnchecked(); //消息回收
}
}
5. looper的quite会调用MessageQueue的quite.然后在loop中遍历的msg就是null,然后Looper的循环就结束了.
public void quit() {
mQueue.quit(false);
}
public void quitSafely() { //这两个方法的区别是,上边会直接结束loop()方法的循环,下边会等loop()将MessageQueue中的消息都处理完在结束loop()循环.
mQueue.quit(true);
}
可见.Looper就是一个控制器,不断把MessageQueue中的msg取出交个msg对应的Handler去处理.
4. Handler 兼顾发送消息和处理消息.
1. 先看成员变量
final MessageQueue mQueue; //handler
final Looper mLooper;
final Callback mCallback; 内部接口,只有一个 handleMessage(Message msg); 方法
2. 看构造方法,最后走向两个构造方法,
public Handler(Callback callback, boolean async) {
//忽略
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
//所以说,Handler所在的线程一定要有Looper,不然就会出错.
3. Handler的sendMessage 和post 最终都会走入下边的方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); //把消息和消息需要执行的之间加入到MessageQueue的消息链表中
}
//同样 移除消息也是调用MessageQuene的移除方法
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
4.所以,handler把msg发出后,就到了MessageQueue中了,然后Looper就阻塞式的取消息,当消息的执行时间到达,Looper就调用hander的dispatchMessage 来处理消息
public void dispatchMessage(Message msg) {
if (msg.callback != null) { //callback就是 Handler.post(Runnable) 的那个对象
handleCallback(msg); //调用runnable的 run方法
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) { 这是handler内部类的执行方法,直接实现Handler时,就需要实现这种方法. new Hander(){ handlerMessage(); }
return;
}
}
handleMessage(msg); //常规的执行方法 这是我们写内部类继承handler时的写法
//public class A extends Handler{ handlerMessage() }
}
}
其实就是三种不同的 实现方式,handler会根据实现方式调用对应的方法.
5.主线程中,系统自动为我们的Handler创建了Looper, 主线程是ActivityThread,入口方法是main,
public static void main(String[] args) {
//忽略 ---
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler(); getHander 返回的是 mH
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}