在网上可随意找到关于这三者之间的关系,但总是没有在代码的角度上分析它们之间的关系。今天就在代码的角度上,理解一下这三者的关系。
1.先看handler。
1)handler代码中重要的三个属性:
final MessageQueue mQueue; final Looper mLooper; final Callback mCallback;
在handler 的默认构造函数中,有这样的代码:
mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = null;
可以看出handler对应于一个looper,而这个looper是在当前主线程中唯一的looper,另外,messageQueue也是从looper中的messageQueue获取。
/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. */ public interface Callback { public boolean handleMessage(Message msg); }
属性中的mCallback就是此回调接口的一个实例,可以避免另外实现Handler来处理message。
此外,handler的四个构造函数,都是在为这几个属性赋值进行实例化,就不在此列出了。
另外,还有一个重要的方法就是dispatchMessage,handler中的message接收处理就是通过此方法来调用处理:
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
2. 接下来是looper,官方有很好的解释,就不在翻译了(翻译的不好)。
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped. Most interaction with a message loop is through the Handler class. This is a typical example of the implementation of a Looper thread, using the separation of prepare() and loop() to create an initial Handler to communicate with the Looper. class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
可以看出一个线程拥有一个message looper。在looper类中,其拥有两个属性
final MessageQueue mQueue; final Thread mThread;
通过prepare方法保证其只有一个looper。
public static void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); }
在looper内的loop方法中,通过获取looper内的messageQueue,用while(true)来循环遍历当前的messageQueue,并通过message的target的dispatchMessage方法来触发handler的sendMessage方法。
public static void loop() { Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } 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(); while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } long wallStart = 0; long threadStart = 0; // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); wallStart = SystemClock.currentTimeMicro(); threadStart = SystemClock.currentThreadTimeMicro(); } msg.target.dispatchMessage(msg); if (logging != null) { long wallTime = SystemClock.currentTimeMicro() - wallStart; long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); if (logging instanceof Profiler) { ((Profiler) logging).profile(msg, wallStart, wallTime, threadStart, threadTime); } } // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long 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.recycle(); } } }
再来看looper的私有构造函数:
private Looper() { mQueue = new MessageQueue(); mRun = true; mThread = Thread.currentThread(); }
可以看到looper是跟当前主线程绑定的。
3. 要了解MessageQueue,先看下Message实体。在Message中重要的字段属性,大家常常都用到,其中我感觉重要的有两个:一个是Handler target;另一个是Message next;有了next,我们便可以知道MessageQueue是如何添加message以及删除Message了以及message的遍历。
好了,先介绍到这里了,内容有点略简单,更多内容感觉还得研读代码,能够调试源码程序更好了。
PS:第一次写博客,有不足的地方,大家家多多指正,非常感谢。