本文共 10242 字,大约阅读时间需要 34 分钟。
handler消息机制原理:本质就是在线程之间实现一个消息队列(MessageQueue)。
生产者Handler在异步线程通过sendMessageDelayed() 将消息添加至MessageQueue, 消费者Looper通过loop()中死循环将MessageQueue中的msg取出后发送给产生此msg的handler的handleMessage() 在主线程进行处理;public Handler(Callback callback, boolean async) { //mLooper每个线程只有唯一一个Looper 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; }
sendMessageDelayed将msg发送至消息队列中
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); }
looper将msg分发到这里,然后接受消息的线程处理msg
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } // 接受msg的线程处理消息 handleMessage(msg); } }
public final class Message implements Parcelable { /** *用户定义的消息代码,以便收件人可以识别此消息的内容。每个{@link Handler}都有自己的消息代码名称 *空间,因此您不必担心与其他处理程序冲突。 */ public int what; /** * 可选的Messenger,可以发送对此消息的回复。确切如何使用它的*语义取决于发送者和接收者。 */ public Messenger replyTo; /** * 可选字段,指示发送消息的uid。这仅对{@link Messenger}发布的消息有效;否则,它将是-1。 */ public int sendingUid = -1; /*package*/ int flags; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; // 我们存储这些东西的链表 /*package*/ Message next;
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
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; 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); } try { //lopper在这里根据msg.target(handler)分发msg msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } }
//底部是链表的形式获取msgMessage next() { final long ptr = mPtr; if (ptr == 0) { return null; } 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) { // 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; } }
Handler中looper最后把msg发送到该方法:public void dispatchMessage(Message msg) { if (msg.callback != null) { //1、线程定时运行 handleCallback(msg); } else { if (mCallback != null) { //2、mCallback的回调方法 if (mCallback.handleMessage(msg)) { return; } } //3、handler的方法 handleMessage(msg); } }private static void handleCallback(Message message) { message.callback.run(); }
1)、定时运行某一线程:public final boolean post(Runnable r)
2)、1)不满足时,然后当callBack不为空时,会回调callBack的handleMessage()方法:public Handler(Callback callback) { this(callback, false); }public interface Callback { public boolean handleMessage(Message msg); }
3)、以上1)、2)都不满足时,调用handler的 handleMessage()方法;
例1:
private Runnable mNextRunnable = new Runnable() { @Override public void run() { mHandler.removeCallbacks(mNextRunnable); if(isCycle()){ setCurrentItem(getCurrentItem() + 1, true); mHandler.postDelayed(mNextRunnable, mDelayTime); } } };
例2:
new Handler().postDelayed(new Runnable() { @Override public void run() { Activity activity = (Activity)context; if (activity != null && !activity.isFinishing()) { ToastUtil.makeToast(context,“ OK ”, Toast.LENGTH_SHORT).show(); } } }, 1000);
由以下代码知道:当时间到了才将msg加到队列中
MessageQueue中: boolean enqueueMessage(Message msg, long when) { msg.when = when; Message p = mMessages; boolean needWake; //当时间到了才将msg加到队列中 if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; } else { 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; }
1、当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用(不然你怎么可能通过Handler来操作Activity中的View?)。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。
2、另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。举例:
public class LeakCanaryActivity extends AppCompatActivity private Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; Message message = Message.obtain(); message.what = 1; mHandler.sendMessageDelayed(message,10*60*1000); }}
线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
private void recycle() { mExecutor.shutdownNow(); }
如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。
/** *删除消息队列中任何待处理的Runnable */ public final void removeCallbacks(Runnable r) { mQueue.removeMessages(this, r, null); }
例:
private void recycle() { if (mHandler != null) { mHandler.removeCallbacks(null); } }
静态类不持有外部类的对象,所以你的Activity可以随意被回收。代码如下:
static class MyHandler extends Handler { @Override public void handleMessage(Message msg) { mImageView.setImageBitmap(mBitmap); }}
但其实没这么简单。使用了以上代码之后,你会发现,由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference):
static class MyHandler extends Handler { WeakReferencemActivityReference; MyHandler(Activity activity) { mActivityReference= new WeakReference (activity); } @Override public void handleMessage(Message msg) { final Activity activity = mActivityReference.get(); if (activity != null) { mImageView.setImageBitmap(mBitmap); } }}
转载地址:http://uhaji.baihongyu.com/