Android Handler机制
2017-04-12 00:00
197 查看
Handler想必Android开发的程序猿们都用到过,面试的过程也经常会被问到,可有些人产生疑问:都是Google封装好的,开发中按照API规则使用也没见出现问题,干嘛要刨根问底的去研究呢?
是啊Google封装了那么多的机制,干嘛要问Handler机制呢?也许因为Android开发注重UI的刷新效率,毕竟直接展示用户给数据并与用户交互的,当然要熟知一二了。
Handler的一般用法:开启子线程完成网络、文件保存,查询数据库数据等等一系列的耗时任务,任务完成后通知主线程(main线程)进行UI刷新。
问题一:那么多子线程都通知主线程,想必主线程要按照通知的时间顺利一个个的处理Message?
解决这个问题:这里就用到消息队列--MessageQueue。
问题二:主线程是如何一个个处理消息队类中的消息的呢?
解决这个问题:使用循环机制--Looer。
问题三:主线程开启一个循环机制为什么不会导致阻塞现象呢?
解决这个问题:让主线程等待--wait()。
问题四:有新的消息发送到主线程,如何触发刷新呢?
解决这个问题:唤醒主线程--wake()。
一步步的通过代码深入研究:
首先我们要清楚一点:程序启动时系统已经为主线程开启了循环机制--Looper,监听子线程发送过来的消息。
Looper.java
从loop()函数中看到一个没有终止条件的for循环--死循环。what?千万别怀疑Google工程师们的水平,确实是一个死循环你没看错,可是为什么没有阻塞主线程呢,原因在这行代码:Message msg = queue.next(); // might block(主体部分)
注释已经很清晰明白的告诉你这句是主要代码,下文会讲解。这里先说明一点,如果消息队列中没有消息时,这里是不会返回null Message对象的,如果真是返回了null,那就意味着线程退出,如果是主线程--程序被kill掉了,既然不会返回null,那就很好理解了,问题三也说过了那就是在这里发生了线程等待--wait(),何时被唤醒,下文会讲到。
注意这行代码:msg.target.dispatchMessage(msg);//该方法中调用了Handler的handleMessage(Message msg)函数。
Handler.java
通过Handler发送Message:
Handler.java:
通过一系列的调用,最终调用的是MessageQueue的enqueueMessage(Message msg, long when)函数。
MessageQueue.java
注意这行代码:nativeWake(mPtr)//调用本地方法,目的唤醒线程。
MessageQueue类中重要的方法next()
注意这行代码:nativePollOnce(ptr, nextPollTimeoutMillis);//条用本地函数,让线程等待--wait()
是啊Google封装了那么多的机制,干嘛要问Handler机制呢?也许因为Android开发注重UI的刷新效率,毕竟直接展示用户给数据并与用户交互的,当然要熟知一二了。
Handler的一般用法:开启子线程完成网络、文件保存,查询数据库数据等等一系列的耗时任务,任务完成后通知主线程(main线程)进行UI刷新。
问题一:那么多子线程都通知主线程,想必主线程要按照通知的时间顺利一个个的处理Message?
解决这个问题:这里就用到消息队列--MessageQueue。
问题二:主线程是如何一个个处理消息队类中的消息的呢?
解决这个问题:使用循环机制--Looer。
问题三:主线程开启一个循环机制为什么不会导致阻塞现象呢?
解决这个问题:让主线程等待--wait()。
问题四:有新的消息发送到主线程,如何触发刷新呢?
解决这个问题:唤醒主线程--wake()。
一步步的通过代码深入研究:
首先我们要清楚一点:程序启动时系统已经为主线程开启了循环机制--Looper,监听子线程发送过来的消息。
public final class ActivityThread { public static void main(String[] args) { ... Looper.prepareMainLooper(); ... Looper.loop(); ... } }
Looper.java
/** * 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(); 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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } 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(); } }
从loop()函数中看到一个没有终止条件的for循环--死循环。what?千万别怀疑Google工程师们的水平,确实是一个死循环你没看错,可是为什么没有阻塞主线程呢,原因在这行代码:Message msg = queue.next(); // might block(主体部分)
注释已经很清晰明白的告诉你这句是主要代码,下文会讲解。这里先说明一点,如果消息队列中没有消息时,这里是不会返回null Message对象的,如果真是返回了null,那就意味着线程退出,如果是主线程--程序被kill掉了,既然不会返回null,那就很好理解了,问题三也说过了那就是在这里发生了线程等待--wait(),何时被唤醒,下文会讲到。
注意这行代码:msg.target.dispatchMessage(msg);//该方法中调用了Handler的handleMessage(Message msg)函数。
Handler.java
/** * 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); } } /** *我们就是重写的这个函数刷新UI的 *Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }
通过Handler发送Message:
Handler.java:
boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } boolean sendMessageDelayed(Message msg, long delayMillis) { ... return sendMessageAtTime(msg, SystemClock.uptimeMillis+delayMillis); } public sendMessageAtTime(Message msg, long uptimeMillis) { ... return enqueueMessage(queue, msg, uptimeMillis); } boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { return queue.enqueueMessage(msg, uptimeMillis); }
通过一系列的调用,最终调用的是MessageQueue的enqueueMessage(Message msg, long when)函数。
MessageQueue.java
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) { 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) { // 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; 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; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
注意这行代码:nativeWake(mPtr)//调用本地方法,目的唤醒线程。
MessageQueue类中重要的方法next()
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) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // 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; } } 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) { // 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; } }
注意这行代码:nativePollOnce(ptr, nextPollTimeoutMillis);//条用本地函数,让线程等待--wait()
相关文章推荐
- Android的Handler机制
- Android笔记--handler机制
- (转)Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- android--handler机制的原理
- Android平台Looper、Handler机制讲解
- (转)Android笔记--handler机制
- Android中的Handler机制
- Android Handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android笔记--handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- android handler机制
- android handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android handler机制
- Android Handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制