消息驱动
Android的应用程序是典型的通过消息驱动的程序,我们知道平时我们运行的Main方法,如果没有阻塞或者等待的话运行完就会退出,为了保持运行就需要阻塞或者死循环之类的方式保持程序的运行,而Android启动一个应用程序的时候同样也会启动一个主线程(UI线程),通过Looper一直循环读取MessageQueue中Message,一旦有新的Message就通过Handler来执行。
Looper
- 启动
进入应用程序时会调用ActivityThread1的main方法
public static final void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
Looper.loop();
......
thread.detach();
......
}
可以看到先调用了Looper的prepareMainLooper(),然后调用了loop()。然后我们再分别看这两个方法
- prepareMainLooper()
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
可以看到实际上调用了prepare方法,参数为false
- prepare()
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));
}
方法中的sThreadLocal是ThreadLocal类的一个实例,用来在线程中存储变量。首先判断线程中是否已经存在了Looper,如果有的话抛出异常,可以看到这个prepare方法只能够被调用一次,如果为空的话new一个Looper实例set进sThreadLocal保存.
- Looper构造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在new Looper实例的时候新建了一个MessageQueue实例,之前一直看到的quitAllowed
是用来标记MessageQueue实例是否可以调用它的quit()
方法的。最后看下最重要的loop方法
- loop()
public static void loop() {
final Looper me = myLooper(); //return sThreadLocal.get(); 就是返回之前set进sThreadLocal的Looper实例
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
//可以看到一定要先调用Looper.prepare() 方法后才能调用loop方法
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//进入无限循环
for (;;) {
//取一条message,如果消息队列中没有消息的话会进入阻塞
Message msg = queue.next(); // might block
//如果取出的消息是null的话表示这个message queue已经调用了quit方法。前面看到主线程中的MessageQueue的quitAllowed为fasle,不允许退出,所以间接的主线程中的loop方法也不会return
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
//调用msg的target实例的dispatchMessage方法,其中的target就是handler,后面会讲到
msg.target.dispatchMessage(msg);
......
}
msg.recycleUnchecked();
}
}
通过上面的一些方法可以看到Looper人如其名,主要就是一直循环从MessageQueue中取Message,取出Message后交给它的target(Handler)进行处理(dispatchMessage)
Handler
这个我们大家肯定非常熟悉,我们经常会遇到在非主线程中需要更新UI需求,这里就会用到Handler了,一般是在这样
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
//处理消息,更新UI
......
}
};
new Thread(new Runnable() {
@Override
public void run() {
......
//耗时操作,发送消息
handler.sendMessage(message);
}
}).start();
- Handler构造方法
public Handler(Callback callback, boolean async) {
//这个会判断一个警告,意思是说Handler class应该是一个静态类,否则可能导致内存泄漏,至于为什么可以参考链接http://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler,同时也会发现上面给出的Handler的用法不是很安全。
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +klass.getCanonicalName());
}
}
//获取与handler同一个线程中的Looper,因为是在主线程中创建的handler,所以这里获取到的就是上文ActivityThread中创建的Looper
mLooper = Looper.myLooper();
//这个可以看到如果想在我们自己的线程中使用handler,一定要先调用Looper.prepare(),主线程中系统已经为我们调用了
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//关联Looper中的MessageQueue
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
-常用的sendMessage及其调用的方法
public final boolean sendMessage(Message msg)
{
//调用了下面的sendMessageDelayed方法
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
//接着调用了sendEmptyMessageDelayed
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
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;
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);
}
可以看到上面一连串的调用,最终调用的还是最通用的sendMessageAtTime方法,我们自己设计方法的时候可以参考一下这种从特殊到通用的形式。接下来我们就要看下这个终极调用的enqueueMessage(queue, msg, uptimeMillis)方法
- enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//这里就可以看到message里面的target到底是什么了,this就表示的这个handler实例自己本身
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//这里将message加入到MessageQueue队列中去
return queue.enqueueMessage(msg, uptimeMillis);
}
这里我们就知道了上文中提到的msg.target.dispatchMessage(msg);中的target就是handler,最后我们就要看下dispatchMessage到底是怎么处理message的了
- dispatchMessage
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//按照上文的用法,最终调用了这个方法
handleMessage(msg);
}
}
按照上文handler的用法我们没有定义msg.callback,new的handler也没用传mCallback,所以最终执行了handleMessage(msg);
这个方法。
- handleMessage
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
可以看到这是个空方法,是不是想起了什么,这不就是我们new Handler的时候覆盖的方法吗,所以最终收到Message后的执行代码到了主线程里面我们覆盖的handleMessage方法中了,所以我们就可以愉快的做更新UI之类的操作了。handler还有一个我们常用的方法post,再看下post到底是怎么回事。
- post(Runnable r)
//有时候我们可能会这样使用
handler.post(new Runnable() {
@Override
public void run() {
txtHandler.setText("456");
}
});
//下面是post的源码,看注释可以知道post的参数Runnable只是为了加入到消息队列中被执行的,执行的线程仍然是handler所在的线程,并没有创建新的线程,所以当我们的handler在主线程中创建时我们还是可以愉快的在Runnable的run方法中更新UI
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*/
public final boolean post(Runnable r)
{
//这里又是一连串的从特殊到通用方法的调用,下面一次贴出来
return sendMessageDelayed(getPostMessage(r), 0);
}
//这里是上面post中被调用的方法
private static Message getPostMessage(Runnable r) {
//不需要直接new,而是直接用Message.obtain(),我们查看obtain方法可以看到内部维护的message池,可以让我们更好的复用message,所以比较推荐这种用法
Message m = Message.obtain();
//然后把我们传进来的Runnable赋给了message的callback,并把这个message实例返回
m.callback = r;
return m;
}
//这里是上面post中被调用的方法
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
//发现这个post的方法和sendMessage方法最终都调用了这个方法,就是把message加入到了message queue中去了,不同的是这次的msg.callback不为null了
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
- 再看dispatchMessage
public void dispatchMessage(Message msg) {
//这次通过handler的post方法这个条件就成立了
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
//上面的handleCallback(msg);调用的方法
private static void handleCallback(Message message) {
//从上文代码知道callback其实就是我们通过post方法传进来的Runnable对象,这里调用它的run方法。
message.callback.run();
}
总结
上文总共涉及到了Looper,Handler,Message,MessageQueue四个对象,主要讲的是他们在UI线程中是如何工作的:当android应用程序启动时会调用Looper的prepare和loop方法,这样就有了一个无限循环,循环的就是MessageQueue里面放的Message,我们可以在主线程中定义Handler,通过Handler来发送Message以及通过定义Handler时覆盖的handleMessage方法或者调用post方法时传入的Runnable的run方法来处理Looper在MessageQueue中取得的Message。当然在我们自己的线程中也是可以用Looper,Handler,只不过需要我们自己调用Looper的方法,android也为我们提供了HandlerThread来方便我们开发。语言描述能力有限,最后用一张图来总结:
参考:
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
Android应用程序消息处理机制(Looper、Handler)分析
Android中Thread、Handler、Looper、MessageQueue的原理分析