Android 深入理解Handler, Looper, Message 三者之间的关系
2017-03-02 08:59
471 查看
Handler, Looper, Message三者之间的关系基本上是面试官必问问题之一,那今天让我们从源码的角度来解读一下它们之间的关系
Handler 构造
以上就是Handler的构造方法,下面我们来分析下两个重点
通过myLooper方法得到一个Looper,sThreadLocal存放的Looper,是主线程main方法中创建的
mQueue 为消息队列,是从Looper中获取,接下来看它发送消息的逻辑
Handler 发送消息
上面代码经过层层调用,最终把消息插入到MessageQueue 队列中(queue队列就是在构造方法中从Looper得到的 )
从构造方法和发送消息可以得出:首先得到主线程创建的Looper对象,然后得到Looper对象中的MessageQueue,然后发送消息到MessageQueue队列当中,插入消息队列以后要如何处理呢?我们来看看Looper的一些方法
Looper prepare方法
主线程在创建的时候会调用Looper的prepare和loop方法,那prepare方法里面干了什么呢?
创建一个Looper对象然后存放到sThreadLocal中,而Handler对象中的Looper就是从sThreadLocal中获取的,接下来看看loop方法
首先得到looper里的消息队列,然后循环从消息队列里取message,最后调用message里target的dispatchMessage方法,target就是发送消息的Handler对象
主要看handleMessage方法这行代码,handleMessage需要我们自己去实现,下面这行代码什么时候会调用呢?
这段代码是什么意思呢?这里涉及到发送消息的另外一种方式,我们有时候为了简单会这样调用
从getPostMessage方法中可以看到,首先从消息池中得到消息对象,然后把我们创建的Runnable对象赋值给消息的callback属性,我们回过头看看上面的判断代码,判断callback是否为空,不为空调用handleCallback方法
方法里面就是回调callback的run方法,run方法就是我们自己的业务逻辑代码
总结
到此三者之间的关系已经分析完毕,主线程在创建时创建Looper对象,在Looper构造方法中创建消息队列MessageQueue,调用Looper的loop方法启动消息循环;然后Handler在创建时从sThreadLocal中取主线程Looper对象中MessageQueue,发送消息插入到消息队列,loop循环取出消息,调用Handler的handleMessage方法或callback回调方法完成消息处理,所以Handler对象必须关联一个Looper对象,在子线程中使用Handler必须要调用Looper的prepare和loop方法,因为它需要Looper的消息队列和消息循环处理,而主线程在创建时已经创建了Looper对象,并启动了Looper循环,所以在主线程中使用Handler不需要调用这2个方法。
Handler 构造
//主线程创建Handler Handler handler = new Handler(); public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { 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()); } } 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 = callback; mAsynchronous = async; }
以上就是Handler的构造方法,下面我们来分析下两个重点
mLooper = Looper.myLooper(); public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
通过myLooper方法得到一个Looper,sThreadLocal存放的Looper,是主线程main方法中创建的
mQueue = mLooper.mQueue;
mQueue 为消息队列,是从Looper中获取,接下来看它发送消息的逻辑
Handler 发送消息
handler.sendMessage(new Message()); public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } 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); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
上面代码经过层层调用,最终把消息插入到MessageQueue 队列中(queue队列就是在构造方法中从Looper得到的 )
//把Hander对象赋值给消息的target 的属性 msg.target = this;
从构造方法和发送消息可以得出:首先得到主线程创建的Looper对象,然后得到Looper对象中的MessageQueue,然后发送消息到MessageQueue队列当中,插入消息队列以后要如何处理呢?我们来看看Looper的一些方法
Looper prepare方法
主线程在创建的时候会调用Looper的prepare和loop方法,那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)); }
创建一个Looper对象然后存放到sThreadLocal中,而Handler对象中的Looper就是从sThreadLocal中获取的,接下来看看loop方法
public static void 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 block if (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 logger Printer 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); } // 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.recycleUnchecked(); } }
首先得到looper里的消息队列,然后循环从消息队列里取message,最后调用message里target的dispatchMessage方法,target就是发送消息的Handler对象
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
主要看handleMessage方法这行代码,handleMessage需要我们自己去实现,下面这行代码什么时候会调用呢?
if (msg.callback != null) { handleCallback(msg); }
这段代码是什么意思呢?这里涉及到发送消息的另外一种方式,我们有时候为了简单会这样调用
handler.post(new Runnable() { @Override public void run() { } }) //调用的post方法 public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
从getPostMessage方法中可以看到,首先从消息池中得到消息对象,然后把我们创建的Runnable对象赋值给消息的callback属性,我们回过头看看上面的判断代码,判断callback是否为空,不为空调用handleCallback方法
private static void handleCallback(Message message) { message.callback.run(); }
方法里面就是回调callback的run方法,run方法就是我们自己的业务逻辑代码
总结
到此三者之间的关系已经分析完毕,主线程在创建时创建Looper对象,在Looper构造方法中创建消息队列MessageQueue,调用Looper的loop方法启动消息循环;然后Handler在创建时从sThreadLocal中取主线程Looper对象中MessageQueue,发送消息插入到消息队列,loop循环取出消息,调用Handler的handleMessage方法或callback回调方法完成消息处理,所以Handler对象必须关联一个Looper对象,在子线程中使用Handler必须要调用Looper的prepare和loop方法,因为它需要Looper的消息队列和消息循环处理,而主线程在创建时已经创建了Looper对象,并启动了Looper循环,所以在主线程中使用Handler不需要调用这2个方法。
相关文章推荐
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android—— Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系【转】
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系