Android的线程消息机制(Handler机制剖析)
2017-09-06 12:25
411 查看
先上handler机制的图片,然后来逐步分析,查看他的源码
从这个构造函数可以看出,如果不是静态的内部类的话,会打印出内存泄漏的警告,而且可以知道在创建线程之前当前线程必须有looper对象,主线程的looper在源码中已经默认实现好了
在看下另外个构造方法
就是简单对传入的looper进行赋值
他其实就是调用
就是为当前时间加上个目标时间,然后穿进去作为参数
可以看到这个方法调用了
从这里可以看出两个事情
1.Message对象被加入MessageQueue的队列中
2.Messagetarget是用来持有Handler的强应用,而Handler如果是非静态内部类,是默认持有外部Activity强引用的,这样就会造成所谓的内存泄漏
除了sentMessage外,还有一种就是
其实就是调用了
最后被送入消息队列中
这两种处理方式有什么区别呢?就在于,第二种实现
当一个消息从队列中被取出时候,会通过
他是通过维护一个链表来构成消息池子的,只要链表中有一个消息对象,就从这里取出
可以看出他是根据when这个时间节点进行排队的,根据时间的排序找到一个合适的Message对象插入队列中
上面逻辑大概就是:判断消息队列中第一个消息是否到达执行时间点,如果满足条件就移除并返回第一个Message对象,否则逻辑往下走执行idlerHandler,所谓的idlerHandler就是在空闲的时候会被执行一次,如果queueIdle返回false的话就会执行之后移除空闲队列
就是创建一个Looper并且存如ThreadLocal中。如果已经存在就抛异常
伪代码如上,就是开启一个循环,不断从消息队列里面取,消息,这个消息队列是一个阻塞队列。
BlockingQueue是个接口,有如下实现类:
1. ArrayBlockQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象必须明确大小,像数组一样。
2. LinkedBlockQueue:一个可改变大小的阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象如果没有明确大小,默认值是Integer.MAX_VALUE。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
Handler源码分析
创建Handler
Handler提供了多种构造方法的重载,主要分为两类,一类是不指定Looper对象,也就是直接使用当前线程的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; }
从这个构造函数可以看出,如果不是静态的内部类的话,会打印出内存泄漏的警告,而且可以知道在创建线程之前当前线程必须有looper对象,主线程的looper在源码中已经默认实现好了
在看下另外个构造方法
public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
就是简单对传入的looper进行赋值
发送消息
使用handler最多的就是sentMessage(message)先看看他的源码
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
他其实就是调用
sendMessageDelayed(Message,long)我们看下这个方法内部
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); }
可以看到这个方法调用了
enqueueMessage(MessageQueue,Message,long)方法,就是让消息去排队
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
从这里可以看出两个事情
1.Message对象被加入MessageQueue的队列中
2.Messagetarget是用来持有Handler的强应用,而Handler如果是非静态内部类,是默认持有外部Activity强引用的,这样就会造成所谓的内存泄漏
除了sentMessage外,还有一种就是
post(Runnable)
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
其实就是调用了
sentMessageDelayed(Message,long),只不过就是把Runable封装进入Message
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
最后被送入消息队列中
处理消息
当消息被丢进消息对垒中,就要被处理,我们经常用Handler就是重写handleMessage(Message)方法来处理Message,其实还有另外一种方式就是实现Handler.Callback接口,这个接口要求必须实现带boolean值得
handleMessage(Message)方法,这两种实现方法如下
private static class MyHandler extends Handler{ @Override public void handleMessage(Message msg) { super.handleMessage(msg); //处理消息, } }
private static class MyHanderCallback implements Handler.Callback{ @Override public boolean handleMessage(Message msg) { return false; } } private Handler myHandler = new Handler(new MyHanderCallback());
这两种处理方式有什么区别呢?就在于,第二种实现
handler.Callback的处理方法是有boolean值得,Handler会优先处理
Handler.Callback实现,然后根据返回值决定是否调用Handler的
handlerMassage(Message)方法,接下来看下
dispatchMessage(Message)方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg);//处理Runable类型消息 } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) {//当Callback.handleMessage返回true时候直接return,就不再执行handleMessage return; } } handleMessage(msg); } }
当一个消息从队列中被取出时候,会通过
dispatchMessage(Message)方法分配给Handler。在处理消息的时候优先处理Runable类型的消息,然后再根据
Handle.Callback.handleMessage(Message)最后才是
Handler.handleMessage(Message)
Message源码分析
Message相当于一个消息媒介,我们通过对这个message对象进行设置,然后最后将他发送出去创建Message
创建消息时我们不是直接newMessage,而是通过Message.obtain()方法,从Message内部维护的一个消息池里面获取一个Message对象,这样的话就可以复用,而不会因为频繁发送消息而造成频繁gc,内存抖动那些,先看看Message源码
public final class Message Implements Parcelable{ private static final int MAX_POOL_SIZE = 50;//消息池最大数量为50 private static Message sPool;//消息池 Message next;//消息池实际上是一个链表结构 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(); } }
他是通过维护一个链表来构成消息池子的,只要链表中有一个消息对象,就从这里取出
回收Message
为了实现复用,Message被处理完后就会回到消息池中,回收的过程就是清空所有数据,全部设置被默认值public void recycle() { if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; } recycleUnchecked(); }
void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. 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++; } } }
MessageQueue源码分析
MessageQueue就是消息队列,我们通过Handler发送消息都会进入到这个Mess个Queue中,之后Looper会提取消息进行处理,看看MessageQUeue源码消息入列
先从他的enqueueMessage(Message,long)源码看下
boolean enqueueMessage(Message msg, long when) { synchronized (this) { msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; } else { //根据时间节点来插入Message 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; } } }
可以看出他是根据when这个时间节点进行排队的,根据时间的排序找到一个合适的Message对象插入队列中
消息出列
接下来看看消息出列的代码,也就是MessageQueue.next()方法,Looper实际上通过这个方法获取下一个要执行的Message对象,
Message next() { int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { 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) do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { //还没有到达时间的情况,就设置一个定时器让他唤醒 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { // Got a message. mBlocked = false; if (prevMsg != null) { //有barrier情况 prevMsg.next = msg.next; } else { //无barrier的情况 mMessages = msg.next; } msg.next = null; 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; } }
上面逻辑大概就是:判断消息队列中第一个消息是否到达执行时间点,如果满足条件就移除并返回第一个Message对象,否则逻辑往下走执行idlerHandler,所谓的idlerHandler就是在空闲的时候会被执行一次,如果queueIdle返回false的话就会执行之后移除空闲队列
关闭队列
void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { //安全的方式关闭队列 //就是对没有到达时间点的消息进行移除,把没有到达时间点的执行完先 removeAllFutureMessagesLocked(); } else { //直接暴力的关闭队列 removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. nativeWake(mPtr); } }
looper源码分析
looper里面包换了一个消息队列,它不断从消息队列获取消息并执行创建Looper
调用LooperPrepare()方法,
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)); }
就是创建一个Looper并且存如ThreadLocal中。如果已经存在就抛异常
执行Looper
创建完Looper之后要做的就是调用Looper.loop()方法让Looper不断从消息队列中获取并处理消息。看下Looper.loop()源码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(); } }
伪代码如上,就是开启一个循环,不断从消息队列里面取,消息,这个消息队列是一个阻塞队列。
BlockingQueue是个接口,有如下实现类:
1. ArrayBlockQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象必须明确大小,像数组一样。
2. LinkedBlockQueue:一个可改变大小的阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象如果没有明确大小,默认值是Integer.MAX_VALUE。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
3. PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。 4. SynchronousQueue:同步队列。同步队列没有任何容量,每个插入必须等待另一个线程移除,反之亦然
相关文章推荐
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- (转)Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android[中级教程] 深入剖析Android消息机制
- 图解 Android Handler 线程消息机制
- Android异步消息处理机制之handler机制
- 【Android 开发】: Android 消息处理机制之三: Handler 中 sendMessage() 源代码剖析
- Android 线程消息机制深入分析