Android:异步消息源码解析

Android:异步消息源码解析

分类:Android进阶

关于异步消息的用法,可以看之前的一篇文章,现在来解析一下源码。

经典用法 Thread {public Handler mHandler;public void run() {Looper.prepare();mHandler = new Handler() {public void handleMessage(Message msg) {// process incoming messages here}};Looper.loop();} }

如此一来,我们便可以在其他线程,通过handler来发送消息给当前线程,达到异步效果。

流程

1、Looper.prepare(); 这个方法辗转调用了下列的方法:

() {prepare(true);}(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException(“Only one Looper may be created per thread”);}sThreadLocal.set(new Looper(quitAllowed));}

prepare方法给ThreadLocal对象set了一个Looper对象,由抛出的异常可以看出每个线程只能有一个Looper对象,那么这个Looper又是用来干嘛的呢?

private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}

Looper绑定了当前线程和MessageQueue。

2、mHandler = new Handler() {…}; 实例化了Handler对象,后面再回来分析这个Handler对象的作用

3、Looper.loop();

() {final Looper me = myLooper();if (me == null) {throw new RuntimeException(“No Looper; Looper.prepare() wasn’t called on this thread.”);}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 msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}// This must be in a local variable, in case a UI event sets the loggerPrinter logging = me.mLogging;if (logging != null) {logging.println(“>>>>> Dispatching to ” + msg.target + ” ” +msg.callback + “: ” + msg.what);}msg.target.dispatchMessage(msg);if (logging != null) {logging.println(“<<<<< Finished to ” + msg.target + ” ” + msg.callback);}newIdent = Binder.clearCallingIdentity();if (ident != newIdent) {Log.wtf(TAG, “Thread identity changed from 0x”+ Long.toHexString(ident) + ” to 0x”+ Long.toHexString(newIdent) + ” while dispatching to “+ msg.target.getClass().getName() + ” “+ msg.callback + ” what=” + msg.what);}msg.recycleUnchecked();}}

第2、6行可以看到,这个方法获取了Looper对象和主要的MessageQueue对象,重点看13、14行,方法内部是一个死循环,不断从MessageQueue里面拉取Message,并且是阻塞式的,也就是说拉不到Message就停在那里了。假设拉到了Message,则调用第27行

msg.target.dispatchMessage(msg);

很明显,就是将消息分发给处理者。而这里的msg.target正是Handler对象。

(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}

我们来分别看下这三个可能,也都是常用情景: ①handler对象post一个任务

handler.post(new Runnable() {() {}});

继续调用

(Runnable r) {return sendMessageDelayed(getPostMessage(r), 0);}private static Message getPostMessage(Runnable r) {Message m = Message.obtain();m.callback = r;return m;}

可以看到handler post进去的任务会赋给message后才进行MessageQueue入队,最终Handler处理这个Message时就会调用这个任务。

②实例化Handler对象时传进一个Callback对象

Handler handler = new Handler(new Handler.Callback() {(Message msg) {return false;}});if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}

最终就会回调这个handleMessage方法。

③最常见的情景,实例化时重写handleMessage(msg)方法,这也是上面消息分发的最后一种可能。

最后两个小问题, 1、Message的MessageQueue入队操作是由Handler对象进行,入队时就会把target设为当前操作的Handler,这样处理消息时就能找到合适的Handler了! 2、主线程的Looper是由系统生成的,找了半天源码没找见,但是官方文档说的很清楚The main looper for your application is created by the Android environment

小结做事的能力往往只能给你一种机会,

Android:异步消息源码解析

相关文章:

你感兴趣的文章:

标签云: