Handler源码分析
0、目录
一、说明
二、源码分析
2.1、使用Handler.sendMessage()方式发送消息
2.2、使用Handler.post()方式发送消息
三、总结
四、感谢
一、说明
本人也是菜鸟,跟着大神的脚步,第一次尝试分析源码,希望自己终有一天也能成为大神。
本文直接进行源码相关的介绍,如果您对Handler相关的使用和工作原理还不是太熟悉,建议您先阅读《Handler使用方法详解(含实例)》和《Handler原理解析》,熟悉相关使用和工作原理后再看相关源码。
二、源码分析
Handler的使用方式因为发送消息的方式不同而不同,总共可以分为两种,Handler.sendMessage()和Handler.post(Runnable r)。
下面的源码分析将根据Handler的这两种使用方式,以及Hander的具体使用步骤进行解析。
2.1、使用Handler.sendMessage()方式发送消息
使用步骤:
使用匿名Handler子类
步骤1、在主线程中通过匿名内部类创建Handler类对象
Handler mhandler = new Handler(){
//重写handleMessage()方法,执行相关的UI操作
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//执行的UI操作
}
};
步骤2、在子线程中创建需要发送的消息对象
Message msg = Message.obtain();
msg.what = 1;
步骤3、在子线程中通过Hander发送消息到消息队列
mhandler .sendMessage(msg);
步骤4、启动子线程
下面将根据每一步进行分析
步骤1、在主线程中通过匿名内部类创建Handler类对象
//使用方法
Handler mhandler = new Handler(){
//重写handleMessage()方法,执行相关的UI操作
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//执行的UI操作
}
};
//源码分析:
public Handler() {
this(null, false);
//this(null, false) = Handler(null, false)
}
public Handler(Callback callback, boolean async){
//仅贴出关键代码
//1、获取当前线程的Looper对象,也就是把Hander与该Looper对象绑定
mLooper = Looper.myLooper();
//public static Looper myLooper() {
// return sThreadLocal.get();//即返回sThreadLocal中存储的Looper对象
// }
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//如果Looper对象为空,则抛出异常
//也就是说当前线程中没有创建Looper对象,则不能创建Handler对象,
//即要想创建Handler对象必须先创建Looper对象
//创建Looper对象方法,主线程中开启应用自动创建,子线程中需要手动调用Looper.prepare()方法
//2、获取Looper对象的消息队列,也就把Handler对象与该消息队列绑定
mQueue = mLooper.mQueue;
}
通过上面的源码我们可以看到,创建Handler对象的时候,会自动关联到当前线程的Looper对象和对应的消息队列上,从而绑定到了实现创建Handler对象操作的这个线程上。
在上面源码中我们直接使用了Looper对象和消息队列,我们并没有创建他们,那么他们是在什么地方创建的,又是如何创建的呢?
步骤1前的隐式操作1、创建Looper对象和MessageQueue对象
创建Looper对象的方法主要分是在主线程还是在子线程中,分别调用Looper.prepareMainLooper()和Looper.prepare(),创建一个Looper对象的同时也会自动创建 一个对应的消息队列对象。两者的区别是,主线程中创建Looper对象在打开应用时自动调用,而在子线程中必须手动调用Looper.prepare()方法来创建Looper对象。
源码分析 Looper.prepareMainLooper()
//作用:为主线程创建一个Looper对象,同时也创建一个MessageQueue对象
//注:该方法在主线程中自动调用,不需要手动调用
//在Android应用进程启动时,会默认创建一个主线程(ActivityThread),
//创建时,会自动调用主线程的main()方法(该方法就是应用程序的入口)
public static void main(String[] args) {
//仅贴出关键代码
//1、为主线程创建一个Looper对象,同时生成一个MessageQueue对象
Looper.prepareMainLooper();-->>分析1
//2、创建主线程
ActivityThread thread = new ActivityThread();
//3、开启消息循环。后面详细介绍
Looper.loop();
//4、消息循环是无限循环,如果退出了该循环,则抛出异常
throw new RuntimeException("Main thread loop unexpectedly exited");
}
//分析1:Looper.prepareMainLooper()分析:
public static void prepareMainLooper() {
//1、也就是调用Looper.prepare()方法,-->>分析2
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
//2、sMainLooper 是一个Looper类型的变量,存放当前Looper对象
//如果其不为空,表示重复创建Looper对象,则抛出异常
throw new IllegalStateException("The main Looper has already been prepared.");
}
//3、获取主线程的Looper对象赋值给sMainLooper
sMainLooper = myLooper();
}
}
分析2 源码分析:Looper.prepare()
//作用:在子线程中创建一个Looper对象,同时生成一个消息对象
//必须在子线程中手动调用Looper.prepare()去创建Looper对象
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//1、static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//通过定义可以看到sThreadLocal 是一个存放Looper对象的ThreadLocal
//即判断sThreadLocal是否为空,是否存在Looper对象,不为空抛出异常
//也就是说一个线程中只能有一个Looper对象,即Looper.prepare()不能被调用两次。
//扩展:ThreadLocal是线程局部变量,当前线程所独有。
sThreadLocal.set(new Looper(quitAllowed));-->>分析3
//2、运行到这,说明是首次创建Looper对象
//新建Looper对象,并存入sThreadLocal中
}
//分析3 Looper构造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
//1、创建消息队列对象
//从这里就能看出来,当创建Looper对象时,同时创建了一个对应的消息队列
mThread = Thread.currentThread();
}
总结:
1、创建主线程时,会自动调用主线程的main()方法,在main()方法内会调用Looper.prepareMainLooper()方法创建Looper对象,同时创建一个消息队列对象。
即在创建Looper对象时,在主线程中是自动创建的,而在子线程中,必须手动调用Looper.prepare()方法调用,若在子线程中没有Looper对象则不能创建Handler对象,也就是说在创建Handler对象前,必须先创建Looper对象。
2、Looper.prepareMainLooper()方法最终依然调用了Looper.prepare()方法。
3、创建完Looper和消息队列后,会自动进入消息循环Looper.loop(),这又是一个隐式操作。
步骤1前的隐式操作2:Looper.loop(),消息循环
源码分析:Looper.loop()
作用:消息循环,主要作用就是从消息队列中获取消息并分发消息到对应的Handler进行处理
public static void loop() {
//仅贴出关键代码
//1、获取当前线程的Looper对象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//如果Looper对象为空,则抛出异常。也就是说,在调用Looper.loop()前必须创建了Looper对象
//2、获取Looper对象中的消息队列
final MessageQueue queue = me.mQueue;
//3、消息循环
for (;;) {
//3.1从消息队列中取出消息对象,如果消息队列为空,则会阻塞.
Message msg = queue.next(); // -->>分析1
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//3.2 消息分发
msg.target.dispatchMessage(msg);// -->>分析2
//msg的target属性的值,就是发送该msg的Handler对象,
//msg.target.dispatchMessage(msg); = Handler.dispatchMessage(msg);
msg.recycle();//释放资源
}
}
分析1:Message msg = queue.next();
作用:从消息队列中取出消息
Message next() {
//仅贴出关键代码
int nextPollTimeoutMillis = 0;
//nextPollTimeoutMillis 用来判断消息队列中是否还有消息
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();
//uptimeMillis() Returns milliseconds since boot, not counting time spent in deep sleep.也就是手机启动以来的时间
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 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) {
if (now < msg.when) {
// 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;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
nextPollTimeoutMillis = 0;
}
...
}
...
}
分析2:msg.target.dispatchMessage(msg);
作用:消息分发,分发给发送该消息的Handler去处理
public void dispatchMessage(Message msg) {
//1、若msg.callback != null成立,则表示该消息的发送方式是Handler.post(Runnable r)
//则执行 handleCallback(msg)方法,在后面分析Handler.post(Runnable r)方式时详细分析.
if (msg.callback != null) {
handleCallback(msg);
} else {
//2、当使用Handler(Callback callback, boolean async)或Handler(Looper looper, Callback callback, boolean async)构造函数
//创建Handler对象时会传入callback对象,并会重写public boolean handleMessage(Message msg)方法,mCallback = callback;
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//3、如果不是以上两种情况,就会运行这里,通常我们写的程序都是执行这里的
handleMessage(msg);//-->>分析3
}
}
分析3: handleMessage(msg)源码分析
/**
* Subclasses must implement this to receive messages.
*/
//可见该方法是一个空方法,创建Handler子类时要重写了该方法(用Handler.post()方法发送消息时则不需要)
public void handleMessage(Message msg) {
}
总结:
消息循环操作主要负责消息出队列和消息的分发
消息分发时,调用msg.target.dispatchMessage(msg)方法进行分发,最终回调重写的handleMessage()方法进行消息的处理。不过在消息分发的时,要进行相关的判断,进而做相应的处理。
步骤2、在子线程中创建需要发送的消息对象
源码分析:Message msg = Message.obtain();
//作用:创建消息对象
//创建消息对象有两种方法,直接new Message()或Message.obtain(),推荐使用第二种方法。
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
//sPool的声明为private static Message sPool,由此可知sPool是一个Message类型的变量
//sPool就是Message内部维持的一个Message池,目的是为了Message的复用。
}
//如果Message池为空,则创建新的Message对象
//从这里就能看出来,获取Message对象时最好使用Message.obtain(),如果Message池为空,依然会 new Message()。
return new Message();
}
总结:
创建消息对象的方法有两个,直接new Message()或Message.obtain(),而者使用了Message池,以便Message的复用,如果Message池,则依然会new Message(),所以创建消息对象时直接使用Message.obtain()即可。
步骤3、在子线程中通过Hander发送消息到消息队列
源码分析: mhandler .sendMessage(msg);
作用:将消息发送到消息队列中
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);//-->>分析1
}
//分析1
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);//-->>分析2
//SystemClock.uptimeMillis() Returns milliseconds since boot, not counting time spent in deep sleep.
//也就是这个时间是手机从启动到现在的时间,而不是系统时间,需要注意。
}
//分析2
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//1、获取对应的消息队列
MessageQueue queue = mQueue;
//2、如果消息队列为空,则抛出异常
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);//-->>分析3
}
//分析3
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//1、这里就是把当前的Handler对象赋值给Message的target属性。
//msg.target在这里赋值,以便在Looper.loop()方法中,
//分发消息时使用:msg.target.dispatchMessage(msg);
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//-->>分析4
}
分析4、MessageQueue下的enqueueMessage()方法
boolean enqueueMessage(Message msg, long when) {
//仅贴出关键代码
...
synchronized (this) {
...
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//判断消息队列有无信息,若无,则当前插入的信息作为队头
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;
//消息msg插入
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
总结:
到此,消息入队列完成,之后Looper对象就会不断从消息队列中读取消息并分发给相应的Handler去处理。
Handler发送消息的关键,Message的target对象绑定到当前发送该消息的Handler,只有这样才能够在分发的时候直到应用分发给哪个Handler处理。
到这里,使用Hander.sendMessage()方法发送消息的源码就分析完成了。
一些总结如下:
2.2、使用Handler.post()方式发送消息
使用步骤:
步骤1、在主线程中创建Handler实例
private Handler mhandler = new Handler();
步骤2、在子线程中使用Handler.post()
mhandler.post(new Runnable() {
@Override
public void run() {
//执行的UI操作
}
});
步骤3、启动子线程
实际Handler.post()方法和Handler.sendMessage()方法大体是一样的,我们仅介绍不同的地方。
下面根据步骤详细分析:
步骤1、在主线程中创建Handler实例
private Handler mhandler = new Handler();
该方式和Handler.sendMessage()方式相同,不同的是这里直接new Handler(),并没有复写handlerMessage().
步骤2、在子线程中使用Handler.post()
//使用方法
mhandler.post(new Runnable() {
@Override
public void run() {
//执行的UI操作
}
});
源码分析
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
//sendMessageDelayed()方法和方式Handler.sendMessage()中的相同
//下面详细分析getPostMessage(r)
}
private static Message getPostMessage(Runnable r) {
//1、创建一个消息对象
Message m = Message.obtain();
//2、把Runnable 直接赋值给了Message的callback属性
m.callback = r;
return m;
}
总结:
通过这里,我们可以看到,Handler.post(Runnable r)方式中,仅仅是把Runnable对象封装到Message对象中去了,而消息的发送,和Handler.sendMessage()方式相同
另外一个重要的区别的地方,就是在分发的时候。
public void dispatchMessage(Message msg) {
//有前面分析我们直到,msg.callback就是Handler.post(Runnable r)中的Runnable对象,
//所以这里不为空,msg.callback != null条件满足,后面执行 handleCallback(msg);
if (msg.callback != null) {
handleCallback(msg); //-->>分析1
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//分析1:
private static void handleCallback(Message message) {
message.callback.run();
//msg.callback就是Handler.post(Runnable r)中的Runnable对象
//message.callback.run() = r.run()
//即回调Handler.post(Runnable r)中Runnable 对象复写的run()方法。
}
总结:
Handler.post(Runnable r)的分析也完成了,通过分析我们可以看到,和Handler.sendMessage()方法主要有两个方面的不同
1、不需要创建任何消息对象,而是直接传入Runnable对象,并把该Runnable对象封装到消息对象中
2、消息的处理方式不同,没有复写handlMessage()方法,而是执行的Runnable对象中的run()方法。
三、总结
以上就是本人对Handler源码相关的分析,对消息发送的两种方式,Handler.sendMessage()和Handler.post(Runnable r),根据每种方式使用步骤进行了详细分析。
四、感谢
第一次尝试分析源码,虽然之前看过很多遍,但真正让自己写出来的时候,特别难,在这里要特别感谢Carson_Ho,读他的文章受益匪浅。