学安卓也有一段时间了,一直都是做项目或者看别人的博客,自己从来没有写一片像样的文章来记录自己所学到的知识,现在发现如果把所学到得知识记录下来对知识也是一种温习,并且会掌握得更加牢固。
今天记录我所掌握的Handler消息机制执行流程,平时我们都会使用到Handler对象来进行延迟消息的处理或者结合线程来更新UI控件,但是对里面的原理也不是很了解,所以我今天看了一下源码,把看到的东西记录下来。
首先我们使用Handler肯定的new一个它的对象,那new的过程当中它都做了些什么事呢?于是乎我打开了源码:
//这里是它的午餐构造方法,它总共有几个构造方法,最终都是调用的这个构造
//方法下面的构造方法
public Handler() {
this(null, false);
}
//最终调用的是这个构造方法
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();//这里可以看到获取了Looper对象
if (mLooper == null) {
//如果looper对象为空,则抛出异常,这里先给出一点疑问,就是,为甚
//么Looper.myLooper()方法可能会为空呢
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//获取消息队列
mCallback = callback;
mAsynchronous = async;
}
当然,获取到Handler对象以后肯定是要使用它的,我们通过调用它的sendMessage(msg)方法或者其他sendXXX方法来发送消息,于是乎我们得有一个消息对象啊,我们可以这么做:
Message msg=new Message()或者Message msg=handler.obtainMessage();大家都知道下面这个方法效率更加高,这是为什么呢请看源码:
public final Message obtainMessage(){
return Message.obtain(this);
}
//最终handler.obtinMessage()会调用Message对象的这个方法:
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
//从上面可以看到,如果使用obtinMessage()方法会先往消息池里面取出,如果去不到则实例化一个返回,这就是为什么obtinMessage比newMessage效率高的原因!
好了,获取到Message对象以后肯定得发送消息啊,于是我们跟踪一下handler.sendMessage(Message msg)方法源码:
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//最终调用了这个方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
...
//可以看到这里会对消息进行排序
return enqueueMessage(queue, msg, uptimeMillis);
}
可以看到发送消息最终会调用enqueueMessage(queue, msg, uptimeMillis)方法,我们进入这个方法一看究竟:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
...
//这里调用了MessageQueue的enqueueMessage方法
return queue.enqueueMessage(msg, uptimeMillis);
}
根据MessageQueue的enqueueMessage方法:
boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
msg.when = when;
Message p = mMessages;
boolean needWake;
//这里判断是否发送消息的延迟时间when 是否为0,如果不是0的话
//则将其加入到队列的前面
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 {
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
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
//从上面的代码可以分析出如果出入的延迟时间为0则优先级最高
//这里是从消息队列中取出消息以后底层调用的方法,好像从这里以后这个方法是系
//底层调用的,查了一下资料貌似是一个linux管道设置的方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//这里调用了handleMessage方法
handleMessage(msg);
}
}
//于是调用了发送消息以后就会调用handlerMessage(Message msg)方法进行我们自己的代码处理了。
具体的流程图可以用如下图来表示:
引入上面我提出的问题,就是在Handler的无参构造方法里:
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();//这里可以看到获取了Looper对象
if (mLooper == null) {
//如果looper对象为空,则抛出异常,这里先给出一点疑问,就是,为甚
//么Looper.myLooper()方法可能会为空呢
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//获取消息队列
mCallback = callback;
mAsynchronous = async;
}
我提出的为什么Looper.myLooper();可能获取的Looper对象为空?首先想一下我们有时候在子线程中创建Handler对象的时候会发生什么情况呢?当然是报错了,这个报错的信息就是上面源码中的提示信息:”Can’t create handler inside thread that has not called Looper.prepare()”,那为什么主线程中new 一个Handler对象就不会报错呢?那是因为在主线程创建的时候系统就会跟着创建一个Looper对象,而子线程中不会主动创建Looper对象,当我们在子线程中先这样写:
Looper.prepare();
....
Looper.loop();
就不会报错了,这里贴出主线程创建Looper对象的源码:
public static void main(String[] args) {
...
Looper.prepareMainLooper();//创建主线程的Looper对象
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();//循环取出消息
所以我们在主线程中new Handler不会报错,在子线程中需要加上Looper.prepare()和Looper.loop()方法的原因了。
具体的流程就分析完毕,如果不对的地方麻烦看的朋友指出一下,我写博客是为了把自己学习的东西记录下来,同时锻炼一下自己的表达能力,希望如果有不对的地方麻烦老师指点一下,谢谢!