Handler机制作为Android面试重要考点,以前笔者都是参考别的优秀博客来了解,大致能够清楚是怎么一回事。然而在不依赖博客的情况下,就只有自己去阅读源码了。作为Android开发,Android源码就是解决问题的源头泉眼。Handler机制涉及的类比较少,代码量相对于庞大的AMS、WMS那些真是如小菜一碟了。Handler机制真正研究起来不需要花很多的时间,不过卡在某个点这种事情也经常发生。希望笔者写的这一篇可以帮助部分读者打通那些卡住的点。
Handler机制涉及的主要的类有Handler、Looper、MessageQueue和Message。
较为常见的是在Activity中声明一个Handler对象出来,这个Handler是主线程的Handler。
public class XXXActivity extends Activity {
……
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 处理返回的消息
if( msg.what == 1 ){
……
}
……
}
};
……
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);// 防止因Handler引起的内存泄漏
}
}
Handler的构造方法:
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
// 平时我们在主线程使用的new一个Handler就是使用这个构造
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async){
……
mLooper = Looper.myLooper();
If(mLooper == null){ // 在主线程中不会执行到这里,因为主线程开启时已经绑定了Looper了
throw new RuntimeException();
}
mQueue = mLooper.mQueue; // Handler的Queue对象与它的Looper对象的mQueue绑定在了一起
mCallback = callback;
mAsynchronous = async;
}
主线程开启时Looper被绑定的代码:
ActivityThread:
public static void main(String[] args){
……
Looper.prepareMainLooper();//绑定主线程Looper
……
Looper.loop();//轮询开始,因为有这句,所以我们在主线程中不需要调用Looper.loop()了,在子线程中实例化Handler对象,需要调用这句话
throw new RuntimeException(“Main thread loop unexpectedly exited”);
}
来看一下Looper的prepareMainLooper方法和与它相关的方法,loop方法是重头戏,先不那么快讲。
Looper:
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
* 这个方法初始化了应用的main Looper,不应该由开发者调用。调用后通过ThreadLocal的性质将主线程和这个Looper绑定,这个Looper就是主线程的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();
}
}
private static void prepare(boolean quitAllowed){
if(sThreadLocal.get() != null){ // ThreadLocal类中get方法的作用是获取属于当前线程的变量的副本
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed)); // 当前线程和Looper对象绑定在一起,线程为键,Looper对象为值
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
/**
* Return the {@link MessageQueue} object associated with the current
* thread. This must be called from a thread running a Looper, or a
* NullPointerException will be thrown.
*/
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
Static final ThreadLocal< Looper > sThreadLocal = new ThreadLocal< Looper >();
上面代码的注释中解释了一下ThreadLocal存储对象的方式:以线程作为键值来存储对象。它就是Handler机制能在线程中切换的关键因素。因此值得再强调一下。
假设线程1 存储 1,线程2 存储 2,线程3 存储 3……,在线程1使用 ThreadLocal对象取值时(调用sThreadLocal.get()),得到 1,在线程2使用ThreadLocal对象取值时,得到2……。
同理可以推广到对象,假设主线程存储Looper对象0,线程1存储Looper对象1,线程2存储Looper对象2,线程3存储Looper对象3……这样的话我们在主线程就能取到Looper对象0了,与其他线程的Looper对象不产生混淆干扰。
private Looper(boolean quitAllowed){
mQueue = new MessageQueue(quiteAllowed);
mThread = Thread.currentThread();
}
可以看到,每个Looper对象都有属于它的MessageQueue对象。
public static void loop(){
final Looper me = myLooper();//一般情况为主线程的Looper
If(me == null){
throw new RuntimeException(“No Looper; Looper.prepare() wasn’t called on this thread.”);
}
final MessageQueue queue = me.Queue;// 主线程的Looper持有的MessageQueue自然也是在主线程中,里面的Message也是主线程的,关键点在于在Handler对象向子线程执行sendMessage方法,Message怎么从子线程跑到主线程了?
……
for(;;){
// 轮询,取出MessageQueue里面的Message对象,next方法是MessageQueue的一个重要方法
Message msg = queue.next(); // might block
if( msg == null){
return null;
}
……
try{
// 调用Handler的handleMessage()方法,返回一些计算结果的话,可以在主线程做更新UI的操作了
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally{
……
}
}
}
Message next(){
……
for ( ; ; ){
……
synchronized(this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessage;
if(msg != null && msg.target == null){ // 还有其它消息要处理
do{
prevMsg = msg;
msg = msg.next; // 链表操作,不断地读取下一个
}while (msg != null && !msg.isAsynchronous());
}
if (msg != null){
if(now < msg.when){
nextPollTimeoutMillis = Math.min(msg.when - now, Integer.MAX_VALUE);
}else{
mBlocked = false;
// 链表数据结构,将要处理的Message取出,标记为使用状态,也就是说处理的这个Message被移除出Message的链表了
if(prevMsg != null){
prevMsg.next = msg.next;
}else{
mMessage = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
}
……
}
}
}
通过我们会在子线程调用Handler的sendMessage方法来发送消息,在handleMessage方法中处理逻辑,这个sendMessage方法最终会调用到sendMessageAtTime方法:
Handler:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;// Handler的MessageQueue对象mQueue就是Looper的MessageQueue对象,Looper的MessageQueue对象与线程绑定,也就是说mQueue和线程绑定。
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // Looper的loop()方法中有 msg.target.dispatchMessage(msg) ,哪个Handler对象发送的消息,返回的结果就由哪个Handler对象来认领处理
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
enqueueMessage方法最终的实现在MessageQueue类中:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
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(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();// Message标记为使用状态
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {// p == null代表之前没有message
// New head, wake up the event queue if blocked.
// 链表数据结构,将msg插到最前面
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 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
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
Handler机制四个类之间的关系就是这样的了,正所谓篇幅不够代码凑,为了使篇幅不至于太少,同时也使意思达到,笔者尽量在代码中插入注释,使读者阅读源码时,通过提示更能理解源码,最重要的是理解源码。如有不正确的地方,欢迎指出,一起在交流探讨中学习成长。