Android源码学习笔记1_消息机制Handler
由于以后以后要从事安卓系统方面的工作,然而本人半个月前还是Android小白. 这几天学习了gityuan的Android操作系统架构, 按照自己喜欢的方式总结一下. 有兴趣的同学可以直接看原博客.
地址:http://gityuan.com/2016/01/01/handler-message-usage/.
Android消息机制的四个类都是在framework/base/core/java/andorid/os/
包下.
framework/base/core/java/andorid/os/
- Handler.java
- Looper.java
- Message.java
- MessageQueue.java
1.事先准备
我准备以gityuan博客上的例子, 以一条线的形式, 把消息传递的工作给描述出来.
首先, 先了解一下这四个类之间的关系.
1.1 Looper类中有以下重要成员变量和方法申明
(这里想说明一点的是, gityuan的博客中介绍Looper时候有个post()
方法, 但是该post()
方法的实现和Handler中post()
方法是一样的, 并且我自己看源码之后发现Looper类中并没有post()
方法)
//这个Looper的引用,用myLooper()方法后指向存储在当前线程本地栈中的Looper
private static Looper sMainLooper;
//ThreadLocal类型的变量, 内部只有一个存储在当前本地栈中的Looper副本
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//每一个Looper还拥有一个MessqgeQueue实例的引用
final MessageQueue mQueue;
//Looper类中保存当前线程的Thread, 在构造器中通过Thread.currentThread获得.
final Thread mThread;
//重要程度递减
public static void loop();
public static void prepare();
public static @Nullable Looper myLooper();
public void quit();
1.2 Handler类中的主要成员变量和方法申明
//Handler在构造器中, 通过myLooper()方法获得Looper, 然后通过Looper.mQueue获得MessageQueue实例的引用
final Looper mLooper;
final MessageQueue mQueue;
//用于消息分发
public void dispatchMessage(Message msg);
//这类方法有很多,他们互相调用,主要是用来队列排列用的.维护Message在队列中的顺序, 最终都是调用Handler类的MessageQueue.enqueueMessage()方法来入队
public final boolean sendMessage(@NonNull Message msg);
//传一个Runable接口类型的实例进去,最后还是调用Handler类的MessageQueue.enqueueMessage()方法来入队, 待会解释
public final boolean post(@NonNull Runnable r);
//Handler类自己的入队方法, 内部调用MessageQueue.enqueueMessage()方法真正入队
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
1.3MessageQueue类
MessageQueue类是一个消息队列, 它的作用就是用来维护消息传递 入队,出队.
它是消息机制的Java层和C++层的连接纽带,大部分核心方法都交给native层来处理. 暂时只要知道它几个方法的作用就行, 不影响本文阅读, 具体想要了解的可以在之后的博客结合native层进行分析.
//构造器
MessageQueue(boolean quitAllowed);
//提取下一条message
Message next();
//添加一条message到队列
boolean enqueueMessage(Message msg, long when);
//从消息队列头部开始中移除message
void removeMessages(Handler h, int what, Object object);
//每一个普通Message必须有一个target,对于特殊的message是没有target,即同步barrier token。
//这个消息的价值就是用于拦截同步消息,所以并不会唤醒Looper.postSyncBarrier只对同步消息产生影响
//对于异步消息没有任何差别。
public int postSyncBarrier()
1.4Message类的主要变量和方法申明
Message中有一个变量池,.
关于该变量池的作用, 如果学过Javaweb可以参考数据库连接池,和Hibernate一级缓存的作用.
也可以看下面obtain()
函数的英文注释
//每个Message都有一个Handler类型的target变量, 表示该Message要被哪个Handler处理.
Handler target;
//Message中的callBack, 可以在Handler.post(Runnable callback)中指定该callback/回调方法
Runnable callback;
//next是一个Message类型的变量, 该变量指向下一个消息池中的Message
//也就是说Message使用类似链表的结构维护了一个消息池
Message next;
//Meaaage类内部有一个消息池, 用一些静态成员构成.
public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
private static boolean gCheckRecycle = true;
//下面两个方法用来维护消息池中Message的还回消息和提取消息
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
//内部实现就是, 从消息池链表的表头取走Message,然后断开链表
public static Message obtain();
/**
* Return a Message instance to the global pool.
* <p>
* You MUST NOT touch the Message after calling this function because it has
* effectively been freed. It is an error to recycle a message that is currently
* enqueued or that is in the process of being delivered to a Handler.
* </p>
*/
//把不再使用的消息加入消息池, 将Message加入到消息池的过程,都是把Message加到链表的表头;
public void recycle()
2.线性探究, 解析消息机制的源码过程
还是用gityuan博客的例子.
代码:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare(); //Looper初始化
mHandler = new Handler() {
public void handleMessage(Message msg) {
//TODO 定义消息处理逻辑.
}
};
Looper.loop(); //开启无限循环的消息分发, 当MessageQueue中没有消息的时候跳出循环
}
}
2.1 我们从Looper.prepare()进入
1)当Looper.prepare()执行之后, 其内部默认调用prepare(true)
的重载, true表示当前Looper允许退出,
2)然后看ThreadLocal类型的sThreadLocal
变量内部是否保存了一个Looper实例.
3)如果还没有, 则实例化一个Looper放在sThreadLocal
中.
public static void prepare() {
prepare(true);
}
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));
}
还是在Looper类中,
我们来看看Looper的这个构造函数Looper(quitAllowed),
4)Looper构造函数中, 先是实例化了一个MessageQueue给自己的mQueue变量,
5)然后允许Looper.prepare的是一个线程吧, 这个线程又运行到Looper构造方法了, 那么Looper的构造方法就把当前的Thread搞到自己mThread中.
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
2.2 看看new Handler()干了啥
现在已经在Handler类了,
1)new Handler()执行之后, 内部调用Handler类自己的另一个构造方法重载.
2)Hander构造的时候, 从当前线程的私有栈中把Looper对象给得到了, 给了mLooper变量
3)我们通过上面的了解已经知道Looper自己是有一个MessageQueue对象的, 变量名为mQueue.
把这个mQueue也给Handler自己的mQueue传递了一个引用.(两个引用指向同一个MessageQueue对象)
4)当然, 由于这里是调用的无参Handler(), 所以callback为null, async为false.
public Handler() {
this(null, false);
}
public Handler(@Nullable Callback callback, boolean async) {
.......
//必须先执行Looper.prepare(),才能获取Looper对象,否则为null.
mLooper = Looper.myLooper(); //从当前线程的TLS中获取Looper对象
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; //消息队列,来自Looper对象
mCallback = callback; //回调方法
mAsynchronous = async; //设置消息是否为异步处理方式
}
2.3 最重要的Loop.loop()
1)Looper.loop()运行之后,首先回去调用该函数线程私有存储的Looper,
2)如果从当前线程获取不到Looper实例, 就抛异常.
3)获取到了就通过该Looper实例me, 获取MessageQueue.
4)之后进入无限循环,从MessageQueue中一直获取下一个Message,如果Message为空loop()
方法就会return,相应的无限循环就会结束.
如果Message不为空, 该Message通过自身target指向的Handler进行消息分发
5)消息完成之后, 把Message放入消息池, 消息池就是上面介绍Message类时说的消息链表.
public static void loop() {
//获取Looper对象
final Looper me = myLooper();
//检查当前线程的私有栈是否已经有Looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//从Looper中获取MessageQueue
final MessageQueue queue = me.mQueue;
.....
for (;;) { //进入loop的主循环方法
Message msg = queue.next(); //可能会阻塞
if (msg == null) { //没有消息,则退出循环
return;
}
//Message通过自身target指向的Handler进行消息分发
msg.target.dispatchMessage(msg);
//将Message放入消息池
msg.recycleUnchecked();
}
}
2.4 假设, MessageQueue中已经有Message了, 那么看看msg.target.dispatchMessage(msg)
是怎么执行的.
很容易知道msg.target.dispatchMessage(msg)
本质就是handler.dispatchMessage(msg)
, 在介绍Handler类方法申明的时候, 我们也知道dispatchMessage()
是Handler类的的成员.
该方法进行Message消息的分发. 它有对于消息的分发是有优先级的.
1:其中Message类中的Runable类型的callback优先级最高,
2:其次是Handler类中内部Callback接口中handlerMessage()方法的自定义实现,
3:最后才是Handler子类实例化重写handleMessage()方法.
具体可以看代码中的注释.
public void dispatchMessage(@NonNull Message msg) {
//第一种: 当Message存在回调方法,优先回调msg.callback.run()方法;
if (msg.callback != null) {
handleCallback(msg);
} else {
//第二种: 当Handler存在Callback成员变量时,回调Handler类内部Callback接口的方法handleMessage();
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//第三种: 优先级最低的是,Handler自身的回调方法handleMessage()
handleMessage(msg);
}
}
第一种: Hadnler类的handleCallback()方法:
private static void handleCallback(Message message) {
message.callback.run();
}
第二种: Handler类中的Callback成员变量和Callback接口
//Callback实际上是Handler类中的一个接口
final Callback mCallback;
//当Handler类实例化的时候, 如果不想通过子类重写Handler类中的handleMessage()方法来实例化的时候
//可以调用Handler类的有参构造函数传入Callback, 构造函数会把mCallback引用到传入的Callback对象.
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
2.5 那到这里有的同学就会很好奇, 这三种消息处理是在啥时候实现的, 是怎么实现的.
第一种是Handler实例调用post()
发送消息的时候
才指定Message.callback (这个callback为Runable类型, 与Handler类中内部Callback接口不是一回事).
Handler类中post()
的源码如下:
在post()
函数中调用了私有函数getPostMessage(Runnable r)
,
这个函数内部调用Message.obtain()
类方法, 从消息池 (就是那个消息链表) 中获得了一个消息, 然后强行指定该消息的callback变量为自己实现的Runable对象, 然后让该消息处理自己想要做的事情.
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
//getPostMessage(r)实现
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
第二种和第三种都是在实例化Handler类的时候去重写的,
第二种重写Handler类内部接口Callback里的handleMessage(@NonNull Message msg)
方法,
第三种是重写Handler类自身的public void handleMessage(@NonNull Message msg) {}
成员方法(源码中对这个方法的解释是:Subclasses must implement this to receive messages).
2.6 发送消息的时候Handler干了啥事
回到2.3
节中, 我们再看看Looper.loop()
方法, 这个方法中msg.target.dispatchMessage(msg)
就是等同于Handler.dispatchMessage(msg)
.
那Message实例中target对象是什么时候赋值的呢?
为什么我们在App开发过程中直接Handler实例调用sendMessage
或者post()
就能等着系统回调该Handler实例中自定义好的handleMessage()
逻辑了呢?
其实在上面的2.5
中, 我们发现Handler.post()
内部其实是调用了sendMessageDelayed()
的发送消息的方法,Handler类发送消息的方法有很多, 无论是sendMessage
, post()
还是sendMessageDelayed()
他们最终都是会调用到Handler类中的enqueueMessage()
方法.
enqueueMessage()方法如下:
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
相信看完这个方法的实现, 所有人都会知道, 默认的msg.target就是this, 就是当前Handler实例.
所以, 只要是发送出去的消息, 每一个普通Message都是有一个默认的target的, 也就是发送消息的Handler实例 (用于拦截同步消息的特殊Message除外).