Handler机制源码解析
来源:互联网 发布:淘宝联盟怎么得佣金 编辑:程序博客网 时间:2024/05/20 17:27
Handler提供了两种方式解决问题(在一个新线程中更新主线程中的UI控件),一种是调用sendMessage方法,一种是通过post方法。
sendMessage方法
通常会重写handleMesaage方法
在另一个线程下调用sendMessage方法(或者其他sendMessageXXX系列方法)
在handleMessage方法中处理信息
post方法
调用post系列的方法,传入参数是Runnable的实现
//handler处理消息Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { //do something } }; ...//sendMessage方法new Thread(new Runnable() { @Override public void run() { Message message = handler.obtainMessage(1,"message"); handler.sendMessage(message); }}).start();...//post方法handler.post(new Runnable() { @Override public void run() { //do something } });
先进入Handler类里面
首先,来看开Handler的构造方法。有很多,但其实只要关注其中的两个就好了
public Handler(Callback callback) { this(callback, false);}public Handler(Looper looper) { this(looper, null, false);}...
所有的构造函数都是调用一下两个构造函数
区别在于,一个使用主线程的Looper,一个可以自己指定Looper
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; } public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async;}
对成员的初始化,分别:
mLooper
、mQueue
、mCallback
、mAsynchronous
所以,还需要涉及两个关键的类
Looper 和 MessageQueue
先看看sendMessage系列的方法和post系列的方法
public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0);}public final boolean postAtTime(Runnable r, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r), uptimeMillis);}public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); }public final boolean postDelayed(Runnable r, long delayMillis){ return sendMessageDelayed(getPostMessage(r), delayMillis);}public final boolean postAtFrontOfQueue(Runnable r){ return sendMessageAtFrontOfQueue(getPostMessage(r));}private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m;}
通过getPostMessage,把runnable接口封装在一个Message里面
这里的Post方法实际上是调用sendMessage系列的方法,传入封装好的Message
那么继续来看开sendMessage系列的方法
public final boolean sendEmptyMessage(int what){ return sendEmptyMessageDelayed(what, 0);}public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis);}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 final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); }
可以看到,以上所以的sendMessag的方法最后都会执行到sendMessageAtTime的这个
方法。
进入sendMessageAtTime方法,其中sendMessageAtFrontOfQueue跟sendMessageAtTime最后都是执行enqueueMessage一样的入队操作。
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);}public final boolean sendMessageAtFrontOfQueue(Message msg) { 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, 0);}private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}
最后,把msg放到队列里面!!!队列就是一开始初始化的mQueue。
再回头看看两个构造函数
//获取主线程中Lopper,mQueue的初始化 mLooper = Looper.myLooper(); mQueue = mLooper.mQueue;//指定一个Looper,mQueue的初始化 mLooper = looper; mQueue = looper.mQueue;
所以,最后会把消息放入当前的Looper持有的队列里面
那么先来看看Looper这个类
Looper是用来使线程中的消息循环起来的。需要知道的是,首先我们要调用Looper的prepare方法,然后调用Looper的Loop方法。过程如下:
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(); } }
进入prepare方法
public static void prepare() { prepare(true);}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)); }private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();} public static Looper myLooper() { return sThreadLocal.get();}
通过 sThreadLocal.set()设置新的Looper,该Looper会持有一个新的队列。
需要注意的是,在一个线程中,只能调用一次Looper.prepare(),因为在第一次调用了Looper.prepare()之后,当前线程就已经绑定了Looper,在该线程内第二次调用Looper.prepare()方法的时候,sThreadLocal.get()会返回第一次调用prepare的时候绑定的Looper,不为null,这样就会抛出异常,throw new RuntimeException(“Only one Looper may be created per thread”),一个线程只能绑定一个Looper对象。
在AcitivityThread中已经执行Looper.prepare();
和Looper.loop();
,所以我们可以直接调用myLooper()
拿到looper,然后直接使用Handler就可以。
但是如果想在另一个线程使用Handler,那么就要重新调用 Looper.prepare();
和Looper.loop();
所以,Looper.prepare();是让当前线程绑定该Looper
接下来就会进入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(); } }
把代码逻辑抽出来,简化后需要关注的关键代码
public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; ... for (;;) { Message msg = queue.next(); // might block ... msg.target.dispatchMessage(msg); ... msg.recycleUnchecked(); } }
逻辑清晰明了
- 拿到当前线程绑定的Looper
- 然后从Looper的队列里面拿出消息
- 接着分发消息。
- 最后回收这个Message
这里注意,queue.next()是会阻塞的。
所以,Looper持有一个队列,并且会一直loop循环从队列拿出消息。
接下来是进去到MessageQueue这个类里面了
先看看这个类的构造函数
MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit();}private native static long nativeInit();
最后会调用到native方法,通过JNI直接和底层的代码打交道,深入底层的源码http://gityuan.com/2015/12/27/handler-message-native/。实际上是选择epoll的方式。
MessageQueue这个类里面有一个Message对象,用来作为队列。这个队列实际上是用链表来实现的。
来看看Message类中常用的部分成员和常用方法
public final class Message implements Parcelable { public int what; ... public Object obj; .... Bundle data; Handler target; Runnable callback; Message next; private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); } void recycleUnchecked() { flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } ... public void setTarget(Handler target) { this.target = target; } ... public void sendToTarget() { target.sendMessage(this); }}
Message通过recycleUnchecked()对message进行回收,spool也是一个链表,把当前对象添加到链表前面,加入到消息池里面。然后可以通过obtain()在消息池里面拿到一个Message,最大值为50。这样,避免了频繁的创建对象和销毁对象了。
Message里面有一个target成员,用来绑定Handler。所以平时使用的 sendToTarget()实际上最后还是调用到Handler里面的sendMessage。
了解完Message的构造
那么回到正题,来主要关注到这一句代码!
Message msg = queue.next();
进入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 (false) Log.v("MessageQueue", "Returning message: " + msg); 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("MessageQueue", "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; } }
源码很多,先简化一下,理清主要逻辑
Message next() { ... int pendingIdleHandlerCount = -1; // -1 only during first . ... for (;;) { ... nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { ... Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { .... prevMsg.next = msg.next; msg.next = null; return msg; } else { // No more messages. nextPollTimeoutMillis = -1; } nextPollTimeoutMillis = 0; } }
现在逻辑已经很多清晰,
如果有msg就返回,nextPollTimeoutMillis = 0,那么在loop里面就继续执行
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
该msg绑定的Handler调用dispatchMessage(msg)把消息分发出去
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
如果有Runnable方法则执行handleCallback方法,最后会执行run方法。
private static void handleCallback(Message message) { message.callback.run();}
否则就执行到我们重写的handleMessage(msg)了,msg就这样发送了过来。
否则如果没有消息,就 nextPollTimeoutMillis = -1
这个nextPollTimeoutMillis会传入到 nativePollOnce(ptr, nextPollTimeoutMillis)中
就会阻塞式地等待获取Message。这里又涉及到了native方法了http://gityuan.com/2015/12/27/handler-message-native/.
回过头再来看看入队enqueueMessage的代码
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("MessageQueue", 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; }
简化代码,最后的逻辑
boolean enqueueMessage(Message msg, long when) { ... synchronized (this) { ... msg.when = when; Message p = mMessages; ... 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 { ... Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } } msg.next = p; // invariant: p == prev.next prev.next = msg; ..... } ..... } return true; }
入队实际上是把消息msg添加到链表最后面
- Handler机制源码解析
- Handler消息机制源码解析
- Handler消息机制源码解析
- Android Handler机制 源码解析
- handler消息机制源码解析
- Handler通信机制源码解析
- Handler消息机制 -- 源码解析
- Handler消息机制源码解析
- Handler机制解析(源码角度)
- Android Handler机制源码解析
- 八、Handler机制源码解析
- android handler机制源码解析
- Handler消息机制源码解析(一)
- Handler消息机制源码解析(二)
- Handler消息机制源码解析(三)
- Handler消息机制源码解析(四)
- Android消息机制Handler源码简单解析
- Android中的Handler机制源码解析
- centos7 安装redis并开机启动
- 选择器中的符号
- 预防ddos攻击常用方法有哪些
- Q&A——性能
- java 表情处理
- Handler机制源码解析
- js跨域 ajax跨域问题解决
- Java NIO系列教程(六) Selector
- prim算法
- iOS之NSData/byte/NSString/char之间的转换
- 【ATSC】韩国:2017年将迎来ATSC3.0广播时代
- redis运行lua脚本hmget返回值为空判断问题
- bzoj4809皇后
- 层级json