Android源码分析笔记--Handler机制
2016-01-12 12:28
369 查看
#Handler机制#
Handler机制实际就是实现一个 异步消息循环处理器Handler的真正意义: 异步处理
Handler机制的整体表述:消息处理线程:
在Handler机制中,异步消息处理线程启动后,该线程在Looper.loop()的影响下会进入无线循环。
获取消息:
在loop()方法的循环中,每循环一次,就从MessageQueue消息队列中取出一个消息。
没有消息的时:
如果消息队列没有消息。那么异步消息处理线程就会进入阻塞等待。
处理消息:
该线程中会回调Handler的handleMessage去处理取出的消息。
消息的来源:
消息来源于在消息处理线程中产生的Handler对象。 每个消息处理线程都可以有多个Handler(当然也可以没有)。Handler对象通过sendMessage方法去把Message放入MessageQueue队列。
源码分析
Looper
1.Handler机制的开始:Looper.prepare()android.os.Looper
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. * Looper.prepare()把当前的线程初始化为一个循环器。 * 这个Looper.prepare()给了当前线程一个创建 持有当前Looper引用的Handler对象的能力。 * 当然,上述这一切必须发生在Looper.loop()前(因为在执行这句话的时候,调用该语句的当前线程就会进入无限循环中) * 注意事项:综上可知,loop要在最后调用。因为loop()之后的语句不会被执行到。 * 可以采用quit()方法退出loop()这个无限循环。 */ public static void prepare() { prepare(true); } /* * *sThreadLocal是ThreadLocal<Looper>的实例对象。这个对象会利用当前线程名作为key,去存储当前线程的Looper对象。 *该方法确保了当前线程只有唯一的一个Looper对象。如果多次调用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对象的创建伴随MessageQueue的生成,结合上面的prepare()方法,意味着一个线程对应一个Looper对象,一个MessageQueue对象 */ private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
结合上述代码可以看出:
Looper.prepare()为当前线程配备了一个Looper对象,一个MessageQueue对象
2.为当前线程 生成对应的Handler对象(一定要在当前线程初始化)
举个例子:
/** * Des:注意: 这里的代码把MyThread变成一个遵循Handler机制的 异步消息循环处理器。 * Created by mahe * Email: madahecoder@163.com */ public class MyThread extends Thread { private static final String TAG = "MyThread"; public Handler mH; //注意:error!下面的注释是错误的初始化方法!因为调用MyThread的线程不是我们MyThread的代码要执行的线程! //假如MyThread在MainActivity中调用new Thread().start(); 那么下面写的Handler其实是与主线程的异步消息处理器相绑定的! //mH = new Handler() { // @Override // public void handleMessage(Message msg) { // Log.d(TAG, "handleMessage: start [msg]"); // // } // }; @Override public void run() { Looper.prepare(); //初始化必须在本线程内执行 mH = new Handler() { @Override public void handleMessage(Message msg) { Log.d(TAG, "handleMessage: start [msg]"); } }; Log.d(TAG, "run: start []" + mH.getLooper().getThread()); Log.d(TAG, "thread loop start"); Looper.loop(); Log.d(TAG, "thread loop"); } public void send() { new Thread(new Runnable() { @Override public void run() { try { sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Log.d(TAG, "run: send Msg"); mH.sendMessage(new Message()); } }).start(); } }
下面进入Handler看看做了什么:
android.os.Handler
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. * 默认构造器把生成的Handler对象和调用new Handler()时,Handler所在的当前线程的Looper进行了绑定。 * 如果当前线程没有Looper,那么这个handler就不能够接受消息。并会抛异常! */ public Handler() { this(null, false); } /** * Use the {@link Looper} for the current thread with the specified callback interface * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) {//这里FIND_POTENTIAL_LEAKS是常量false,所以内部代码忽略掉 ... } mLooper = Looper.myLooper();//这里是重点 if (mLooper == null) {//如果没有拿到looper对象那就抛异常 throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
android.os.Looper
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. * 这里就根据当前线程的线程名拿到关联的唯一的Looper对象实例 */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
总结:
new Handler()把当前线程的Looper实例对象与Handler实例对象绑定
3.当前线程进入无限循环,等待消息来临,并分发掉:Looper.loop()
android.os.Looper
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. * 让消息队列运作起来! */ public static void loop() { final Looper me = myLooper();//拿到当前线程唯一的Looper实例对象 if (me == null) {//再次印证prepare()要先调用 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue;//拿到Looper唯一对应的MessageQueue实例对象 // 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();//清掉UID PID这些身份信息,确保当前线程是在本地进程进行后面的语句调用 final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block,这里是从MQ中取消息,当然队列没消息的时候就会阻塞 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);//这里就是消息的分发,这里的target就是Handler,看到这里,并不知道target实例哪里来的,那就从Message的产生和发送去看 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) {//如果在分发消息前和分发消息后身份信息不一致那就出问题了,意味着要崩溃 /* * What a Terrible Failure: Report a condition that should never happen. The error will always * be logged at level ASSERT with the call stack. Depending on system configuration, a report * may be added to the android.os.DropBoxManager and/or the process may be terminated * immediately with an error dialog. */ 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(); } }
4.Handler发送Message到MQ的过程:
android.os.Handler
/** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. * 把消息放到消息队列的队尾,然后会在初始化这个handler的依附线程中的handleMessage方法中拿到消息 * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. * true 成功放进了消息队列 * flase 没有放进消息队列,主要原因是维护消息队列的looper正在退出中 */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } /** * Enqueue a message into the message queue after all pending messages * before (current time + delayMillis). You will receive it in * {@link #handleMessage}, in the thread attached to this handler. * 延迟发送消息 * @return Returns true if the message was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. Note that a * result of true does not mean the message will be processed -- if * the looper is quit before the delivery time of the message * occurs then the message will be dropped. * 注意:true 放入MQ成功,但是并不意味着消息会被MQ分发出去。 * 例如:looper调用了quit进行退出操作。然后handler这边延迟10s去发送消息 * 那这里也会返回true,handler把消息发送了出去但是MQ会把这个消息会被丢弃。 */ 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;//在这里即将发给MQ前把msg的目标target指定为自身 if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);//Handler实例把msg放进了消息队列 }
在MessageQueue中查看处理过程:
android.os.MessageQueue
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) {//一般情况下,放入MQ的动作实在其他线程做的异步操作,所以要加同步锁 if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) {//从这里可以看出: MQ里面的消息之间是采用单项链表的结构串在一起 //p就是previous。表示之前的消息。 //如果p == null,说明我们传进来的msg是头一个。 如果when == 0 表示立即处理。 when < p.when表示插在p消息之前处理。 //以上情况都让本msg优先处理,也就是放在链表的头位置,mMessage就是链表头的位置 // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) {//循环的作用是让最终prev指向链表中的最后一个元素,让p指向null prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg;//这里的两句代码就是把当前的msg作为最后一个元素放进链表中。 } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
循环的作用是让最终prev指向链表中的最后一个元素,让p指向null。这里的两句代码就是把当前的msg作为最后一个元素放进链表中。
可以画图看一下,会更加明显!
这样msg就放进了MQ的单向链表中!
6.回到Loop循环去看如何从MQ取出msg并分发
android.os.Looper
//精简后的核心逻辑是这样的
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // might block当异步消息回来之后进行后续的当前线程的处理 if (msg == null) { // No message indicates that the message queue is quitting. return; } msg.target.dispatchMessage(msg); msg.recycleUnchecked(); } }
进入queue.next()分析:
android.os.MessageQueue
//代码比较长,但并不是特别复杂 Message next() { // Return here if the message loop has already quit and been disposed. // This can happen if the application tries to restart a looper after quit // which is not supported. final long ptr = mPtr; if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) {//没有消息的时候nextPollTimeoutMillis为-1 Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis);//没有消息的时候代码会阻塞在这里 synchronized (this) {//MQ是有可能被其他线程访问的,所以要加锁 // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages;//链表头部的元素 if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // Next message is not ready. Set a timeout to wake up when it is ready. nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else {//通常会走这条逻辑, // Got a message. mBlocked = false; if (prevMsg != null) {//队列里有消息,把当前消息放到队尾 prevMsg.next = msg.next; } else {//队列里没有消息,把消息放在链表头 mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg;//返回msg } } else { // No more messages. nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // If first time idle, then get the number of idlers to run. // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {//当没有消息时进去 pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) {//如果没有闲置处理器在跑那就置位mBlocked,进行等待 // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // We only ever reach this code block during the first iteration. for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; } }
android.os.Looper
//精简后的核心逻辑是这样的 public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } msg.target.dispatchMessage(msg);//拿到msg,然后通过Handler分发出去 msg.recycleUnchecked(); } }
android.os.Handler
/** * 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); } }
这里进行分发处理。注意到,如果msg如果有回调处理,那么就不会交给其他的回调。
回调优先级 msg.callback > mCallback > Handler.handlerMessage
相关文章推荐
- 都在说EventBus,我也来一波EventBus
- Android Studio安装
- 列出android 声卡
- Android下的屏幕适配
- 关于android里的文件创建及读写问题
- android应用程序窗口框架学习(2)-view绘制流程源代码解析-setContentView与LayoutInflater加载解析机制源码分析
- [Andorid开发艺术探索 读书笔记]View的事件体系(一)
- Android编程使用Intent传递对象的方法分析
- Activity生命周期
- android 来电拦截
- Android中的几种小窗口实现
- Android实现QQ抢红包插件
- Android编程获取地理位置的经度和纬度实例
- Android中回调接口使用实例
- android用于打开各种文件的intent
- Android系统 小米/三星/索尼 应用启动图标未读消息数(BadgeNumber)动态提醒
- Android-四元数-控制VR设备的旋转
- 创建手机桌面的悬浮图标
- Android sdk等工具下载地址
- Android SD卡路径问题以及如何获取SDCard 内存