Android中的Handler机制分析(一) Handler和Message分析

作为一个Android程序员,我想大家都知道在做一些比较耗时的操作的时候都不会放在主线程,比如网络请求、数据库操作等(尤其是网络请求,在Android4.0之后强制不能放在主线程中执行,否则抛出android.os.NetworkOnMainThreadException异常),而更新UI的操作的都是由UI线程处理。那么有这样一个需求,我在一个新的线程中获取到数据,然后设置到界面上,这就涉及到了两个线程,用于更新界面的UI线程不知道什么时候数据获取完成可以更新界面了,那怎么办呢?Google就给我们提供了一个解决方案,也就是我们今天主要说明的内容——Android中的Handler消息机制

介绍Handler机制之前,首先了解几个概念:
Message:
消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。
MessageQueue:消息队列,用来存放通过Handler发布的消息并按时间进行排序,按照先进先出执行。
Handler:Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。
Looper:轮询器,扮演MessageQueue和Handler之间桥梁的角色,循环取出MessageQueue里面的Message,并交付给相应的Handler进行处理。

首先来一个简单使用:

private static final int HANDLER_TEST_WHAT = 0x01; // 定义测试what
// 创建Handler对象,并重写handlerMessage()方法处理消息
private Handler handler = new Handler(){
	@Override
	public void handleMessage(Message msg) {
	    int what = msg.what; // 获取消息的what
	    // 通过what对消息进行判断,不同消息不同的处理
	    if(what == HANDLER_TEST_WHAT){
		// 处理消息
	    }
	}
};

// 创建一个子线程发送消息
new Thread(){
    @Override
    public void run() {
	Message message = Message.obtain(); // 创建一个消息对象,使用obtain()重用回收的消息对象
	message.what = HANDLER_TEST_WHAT;   // 设置Message的 what
	handler.sendMessage(message);       // 发送一个消息
    }
}.start();
上面就是一个简单的例子,在子线程发送一个消息,然后在主线程就可以对消息进行处理,当然包括更新UI或者其他操作。


下面我们就从源码的角度查看与分析一下Handler消息机制

(如果打开相关部分的完整源码对照着看效果更好哦~~~)

Message源码分析:

前面说到了Message表示一个消息,可以理解为线程间通讯的数据单元,可以用来传递一些数据。

1.首先看一下Message类中的一些成员变量
public int what:
可以用来区分不同的消息,然后在Handler中做不同的处理
public int arg1,arg2:可以传递数据,当需要传递的数据仅仅是int类型时,可以用arg1和arg2,而不需要使用复杂的obj和data
public Object obj:可以传递数据,可以传递任意的Object对象
Bundle data:可以Bundle类型传递数据,但是使用了默认修饰符,不能直接使用Message对象.data的形式设置和获取值,但Message提供了对应的get和set方法用来设置和获取值
Handler target:保存发送消息的Handler对象,可以在创建Message时指定,在后面会有用到target这个参数,所以特别说明
Runnable callback:Runable对象,可以在创建Message时指定,另外在Handler使用post形式发送消息时的callback参数最终也是保存在Message的这个参数中
Message next:Message对象,用来使Message组成链表的形式

private static Message sPool:用于保存回收的Message消息对象
private static boolean gCheckRecycle = true:判断Android版本是否大于Android5.0(Build.VERSION_CODES.LOLLIPOP),小于为false


2.创建(获取)一个Message对象(以下方法都是使用Public修饰的)

Message(){} // 空参数构造方法,直接new Message()创建对象
static Message obtain() // 使用静态的obtain()方法获取,内部会重复使用回收的Message对象,比较常用
static Message obtain(Message orig) // 根据传递的Message对象复制一个新的Message对象
static Message obtain(Handler h) // 给Message指定Handler,会将 h 赋值给 成员变量 target
static Message obtain(Handler h, Runnable callback) // 给Message指定Handler和Runable,会将 h 赋值给 成员变量 target,callback赋值给Message的成员变量 callback
static Message obtain(Handler h, int what) // 给Message指定Handler和what,赋值给Message中对应的成员变量
static Message obtain(Handler h, int what, Object obj) // 给Message指定Handler、what和Object类型的值,赋值给Message中对应的成员变量
static Message obtain(Handler h, int what, int arg1, int arg2) // 指定Message更多的属性
Message obtain(Handler h, int what, int arg1, int arg2, Object obj) // 指定Message更多的属性


3.Message中的部分方法

// 回收消息Message对象
public void recycle() {
	// 判断是否在使用
	if (isInUse()) {
		// 判断版本,在说成员变量时有说明,如果版本大于5.0就会报错
		if (gCheckRecycle) {
			throw new IllegalStateException("This message cannot be recycled because it "
					+ "is still in use.");
		}
		// 如果该Message对象在使用就返回
		return;
	}
	// 调用回收Message对象的方法
	recycleUnchecked();
}
// 回收消息
void recycleUnchecked() {
	flags = FLAG_IN_USE; // 将标记设置为没有使用
	what = 0; 
	// ...  清除Message成员变量的值

	// 使用同步代码
	synchronized (sPoolSync) {
		// 判断回收消息队列的长度是否大于最大长度
		if (sPoolSize < MAX_POOL_SIZE) {
			// 将回收的消息添加到回收的链表中
			next = sPool;
			sPool = this;
			sPoolSize++;
		}
	}
}
// 给消息指定一个Handler
public void setTarget(Handler target) {
	// 复制给target
	this.target = target;
}
// 给消息设置data值
public void setData(Bundle data) {
	this.data = data;
}
// 获取data,但是当data为null时会创建一个返回
public Bundle getData() {
	if (data == null) {
		data = new Bundle();
	}
	
	return data;
}
// 和getData()方法一样获取data值,但是不会进行判断和创建
public Bundle peekData() {
	return data;
}
// 将消息发送给指定的Handler
public void sendToTarget() {
	target.sendMessage(this);
}
// 设置是否为异步消息
public void setAsynchronous(boolean async) {
	if (async) {
		flags |= FLAG_ASYNCHRONOUS;
	} else {
		flags &= ~FLAG_ASYNCHRONOUS;
	}
}
// 判断消息是否在使用
/*package*/ boolean isInUse() {
	return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
// 将消息设置为使用状态
/*package*/ void markInUse() {
	flags |= FLAG_IN_USE;
}


Handler源码分析:
1.Handler的创建(构造方法):在Handler中的构造方法比较多,但是最终调用的只有两个

// 两个参数的构造方法
public Handler(Callback callback, boolean async) {
	...
	// 通过Looper中的方法myLooper()获取与当前线程绑定的Looper,具体实现在Looper部分说明
	mLooper = Looper.myLooper();
	// 当前线程不是Looper线程,也就是没有调用Looper.prepare()给线程创建Looper对象
	if (mLooper == null) {
	    // 抛出异常
	    throw new RuntimeException(
		"Can't create handler inside thread that has not called Looper.prepare()");
	}
	// 让Handler持有当前线程消息队列(MessageQueue)的引用
	mQueue = mLooper.mQueue;
	// 主要用于Handler的消息发送的回调,优先级是比handlerMessage()方法高,但不常用
	mCallback = callback;
	// 是否异步,如果为true则会调用Message中的setAsynchronous(boolean async)方法,设置参数为true
	mAsynchronous = async;
}
// 三个参数的构造方法
public Handler(Looper looper, Callback callback, boolean async) {
	// 直接赋值,获取Looper中的MessageQueue引用让Handler持有
	mLooper = looper;
	mQueue = looper.mQueue;
	mCallback = callback;
	mAsynchronous = async;
}

我们常用的Handler handler = new Handler();实际上调用的就是两个参数的构造方法。


2.Handler发送消息:发送消息的方法比较多,下面都列出来了

// 1 sendMessage(Message msg)
// 2 sendEmptyMessage(int what)
// 3 sendEmptyMessageDelayed(int what, long delayMillis)
// 4 sendEmptyMessageAtTime(int what, long uptimeMillis)
// 5 sendMessageDelayed(Message msg, long delayMillis)

// 6 前面5个发送消息的方法最终调用的都是这个(第6个)方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
	// 将Handler中的MessageQueue引用赋值给新的MessageQueue对象
	MessageQueue queue = mQueue;
	// 判断MessageQueue是否为null,如果为null抛出一个 RuntimeException 异常
	if (queue == null) {
	    RuntimeException e = new RuntimeException(
		    this + " sendMessageAtTime() called with no mQueue");
	    Log.w("Looper", e.getMessage(), e);
	    return false;
	}
	// 调用Handler的enqueueMessage()方法,并将时间传递过去
	return enqueueMessage(queue, msg, uptimeMillis);
}
// 7 这个方法表示将消息对象(Message)插入到消息队列(MessageQueue)的最前面
public final boolean sendMessageAtFrontOfQueue(Message msg) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
	// 传的时间值为0
        return enqueueMessage(queue, msg, 0);
}
我们接着看Handler中的enqueueMessage()方法:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        // 特别注意:将当前对象(Handler对象)赋值给Message的target变量
	msg.target = this;
	// 根据是否异步调用Message的setAsynchronous()方法
	// 在上面Handler的构造方法中提到过
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
	// 调用MessageQueue的enqueueMessage()方法对Message进行排序
        return queue.enqueueMessage(msg, uptimeMillis);
}
到了这一步,我们看到了在调用Handler中的发送消息方法时,Handler在这里并没有做过多操作,然后就通过参数将Message对象传递到了MessageQueue(消息队列)中,调用的是MessageQueue中的相关方法进行相关操作,在下一篇博客《 Android中的Handler机制分析(二) MessageQueue分析》中我们就会说到。


3.Handler发送一个Runable对象

public final boolean post(Runnable r)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean postAtFrontOfQueue(Runnable r)
以上就是Handler提供用来发送一个Runnable对象到消息队列的方法,在下面我贴出两个方法的源码:

// 通过getPostMessage()方法获取一个消息对象,然后调用sendMessageDelayed()方法
public final boolean postDelayed(Runnable r, long delayMillis){
	return sendMessageDelayed(getPostMessage(r), delayMillis);
}
// 调用sendMessageAtFrontOfQueue()方法将消息添加到消息队列的队首
public final boolean postAtFrontOfQueue(Runnable r){
	return sendMessageAtFrontOfQueue(getPostMessage(r));
}
我们来看一下getPostMessage()方法干了什么事

private static Message getPostMessage(Runnable r) {
	Message m = Message.obtain();
	m.callback = r;
	return m;
}
这个方法获取一个消息对象,并将Runnable赋值给Message的callback变量。

我们看到使用post方式发送一个Runnable对象到消息队列其实在内部使用的也是sendXXX的方式,只是系统帮我们把Runnable对象赋值给了Message的callback变量。

4.Handler移除消息

// 移除Runnable这个消息
public final void removeCallbacks(Runnable r){
	mQueue.removeMessages(this, r, null);
}
// 移除指定了token的Runnable的消息,如果token为null,将移除所有的callback消息
public final void removeCallbacks(Runnable r, Object token){
	mQueue.removeMessages(this, r, token);
}
// 移除指定的what值的消息
public final void removeMessages(int what) {
	mQueue.removeMessages(this, what, null);
}
// 移除指定的what值和object值的消息
public final void removeMessages(int what, Object object) {
	mQueue.removeMessages(this, what, object);
}
// 移除指定的token的消息,如果token为null,将移除所有的消息(callbacks和messages)
public final void removeCallbacksAndMessages(Object token) {
	mQueue.removeCallbacksAndMessages(this, token);
}
由以上方法我们可以看到,Handler并没有对消息进行移除操作,只是调用了MessageQueue中的相关方法对消息对象进行操作,在下一篇博客《 Android中的Handler机制分析(二) MessageQueue分析》我们主要说这个类。

5.Handler中的dispatchMessage(Message msg)方法

public void dispatchMessage(Message msg) {
	// 判断Message中的callback是否为null,也就是判断是否为Runnable类型的消息
	if (msg.callback != null) {
		// 执行Runnable中的run()方法
		handleCallback(msg);
	} else {
		// 如果不是,判断Handler中的mCallback是否为null
		if (mCallback != null) {
			// 不为null,就执行mCallback中的handleMessage()方法
			// 并且如果该方法返回true,就不会执行Handler中的handleMessage()方法了
			// 在Handler的创建这个部分注释中说到了它的优先级更高
			if (mCallback.handleMessage(msg)) {
				return;
			}
		}
		// 执行Handler中的handleMessage()方法,也就是我们在创建Handler对象时候重写的方法
		handleMessage(msg);
	}
}
// 调用Runnable的run()方法
private static void handleCallback(Message message) {
	message.callback.run();
}

说明:前面所说的Handler中的方法(Handler的创建、发送/移除消息等)我们在开发中都调用过,但是对于dispatchMessage()方法我们却并没有调用过,那么它是在哪里调用然后让系统来执行我们的handleMessage()方法呢?不要着急,在这里我们先记住这个方法,在后面的篇博客《Android中的Handler机制分析(三) Looper分析和Handler其他知识》中我们就会说到,其实它是在Looper中被调用的。


最后来个带CallBack的Handler创建方式
private Handler handler = new Handler(new Handler.Callback() {
	@Override
	public boolean handleMessage(Message msg) {
		// 如果返回true,就不会执行下面的那个handleMessage()方法了
		return false;
	}
}) {
	@Override
	public void handleMessage(Message msg) {
		int what = msg.what; // 获取消息的what
		// 通过what对消息进行判断,不同消息不同的处理
		if (what == HANDLER_TEST_WHAT) {
			// 处理消息
			Toast.makeText(MainActivity.this, "hhh", Toast.LENGTH_SHORT).show();
		}
	}
};
接下一篇博客《 Android中的Handler机制分析(二) MessageQueue分析》。


你可能感兴趣的:(Android,源码)