关于这几个之间的关系以及源码分析的文章应该挺多的了,不过既然学习了,还是觉得整理下,印象更深刻点,嗯,如果有错误的地方欢迎反馈。
转载请注明出处:http://www.cnblogs.com/John-Chen/p/4396268.html
对应关系:
files/7e9ea72e-86e5-4ff1-8a22-3ab21e2a3993.png" alt="" border="0" />
1、Handler
不带Looper的构造器
/** * 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 represent 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. */ 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(); //myLooper() return sThreadLocal.get(), mLooper每个线程独有,腾讯有次面试问到了 if (mLooper == null) { //Handler创建时必须有Looper对象 throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
“In Android, Handler classes should be static or leaks might occur.”:
public class MainActivity extends ActionBarActivity { //warn:In Android, Handler classes should be static or leaks might occur. private final Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; }
原因:
no-static的内部类handler会隐式的持有当前类MainActivity的一个引用,Handler 的 post/sendMessage 系列方法最后都是通过转调 MessageQueue 的 enqueueMessage 来实现的,每个Message都持有一个Handler的引用(Message.target),所以最终会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被引用而无法被回收。
解决办法:
1、在关闭Activity的时候停掉与Handler有关的后台线程;
2、如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了;
3、将Handler声明为静态类:
static class MyHandler extends Handler { WeakReference<Activity> mActivityReference; MyHandler(Activity activity) { mActivityReference= new WeakReference<Activity>(activity); } @Override public void handleMessage(Message msg) { final Activity activity = mActivityReference.get(); if (activity != null) { //...... } } };
2、Looper
一个典型的Loop Thread实现:
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(); } }
变量:
//sThreadLocal变量保证looper对象每个线程独享,prepare()中set值 // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //通过Loop.class管理 private static Looper sMainLooper; // guarded by Looper.class //对应1个消息队列 final MessageQueue mQueue; //对应1个线程 final Thread mThread;
Looper构造器:
//Main thread not allowed to quit private Looper(boolean quitAllowed) { //创建一个消息队列 mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
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()}. */ public static void prepare(){ prepare(true); } private static void prepare(boolean quitAllowed){ if (sThreadLocal.get() != null) { //每个线程只能有1个Looper对象 throw new RuntimeException("Only one Looper may be created per thread"); } //线程内创建一个Looper对象 sThreadLocal.set(new Looper(quitAllowed)); } /** * 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) { //必须先调用Looper.prepare() 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. //没有消息表示消息队列已终止,即已调用mQueue.quit(true),消息循环终止 return; } ...... msg.target.dispatchMessage(msg); //通过handler分发消息 ...... msg.recycleUnchecked(); //Recycles a Message that may be in-use } }
MainLooper:
/** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */ public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } /**
Returns the application's main looper, which lives in the main thread of the application. */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } }
ActivityThread.main:
public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); Security.addProvider(new AndroidKeyStoreProvider()); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); //主线程中,系统已经帮我们自动调用了Looper.prepare()方法,所以在主线程中可以直接创建Handler对象 Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); }
Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
3、消息队列MessageQueue
底层实现:
android/frameworks/base/core/jni/android_os_MessageQueue.h
android/frameworks/base/core/jni/android_os_MessageQueue.cpp
epoll模型找到几篇不错的文章:
http://blog.chinaunix.net/uid-7944836-id-2938541.html
http://blog.csdn.net/ashqal/article/details/31772697
http://book.2cto.com/201208/1946.html
Message是链表结构:
public final class Message implements Parcelable { public int what; public int arg1; public int arg2; public Object obj; public Messenger replyTo; public int sendingUid = -1; /*package*/ static final int FLAG_IN_USE = 1 << 0; /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1; /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; /*package*/ Message next; ...... }
MessageQueue变量:
// True if the message queue can be quit. //与 Looper.prepare(boolean quitAllowed) 中参数含义一致,是否允许中止,主线程的消息队列是不允许中止的 private final boolean mQuitAllowed; //MessageQueue 是通过调用 C++ native MessageQueue 实现的,mPtr是指向native MessageQueue的指针 private long mPtr; // used by native code //消息链表 Message mMessages; //表示当前队列是否处于正在退出状态 private boolean mQuitting; // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout. //表示next()调用是否被block在timeout不为0的pollOnce上 private boolean mBlocked;
MessageQueue构造函数:
MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }
native函数:
//创建 NativeMessageQueue 对象,并将这个对象的指针复制给 Android MessageQueue 的 mPtr private native static long nativeInit(); //通过等待被激活,然后从消息队列中获取消息 private native static void nativePollOnce(long ptr, int timeoutMillis); //激活处于等待状态的消息队列,通知它有消息到达了 private native static void nativeWake(long ptr); //消息队列是否是空置状态 private native static boolean nativeIsIdling(long ptr); //销毁消息队列 private native static void nativeDestroy(long ptr);
//添加消息
boolean enqueueMessage(Message msg, long when) { //检测消息的合法性,必须有Handler对象以及未处理 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; //按照时间从小到大,when == 0插入到头部 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. //当前消息队列已经处于 Blocked 状态,且队首是一个消息屏障(和内存屏障的理念一样, //这里是通过 p.target == null 来判断队首是否是消息屏障),并且要插入的消息是所有异步消息中最早要处理的 //才会 needwake 激活消息队列去获取下一个消息 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; }
Handler 的 post/sendMessage 系列方法最后都是通过转调 MessageQueue 的 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); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
Handler 中与Message 相关的静态方法也都是通过 MessageQueue 的对应的静态方法实现的,比如 removeMessages, hasMessages, hasCallbacks 等等。
//取消息
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) { //已经dispose() 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; } }
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); } }
IdleHandler:
IdleHandler接口表示当MessageQueue发现当前没有更多消息可以处理的时候则顺便干点别的事情的callback函数(即如果发现idle了,
那就找点别的事干)。
callback函数有个boolean的返回值,表示是否keep。如果返回false,则它会在调用完毕之后从mIdleHandlers
中移除。
ActivityThread.java里的一个内部类,代码如下:
final class GcIdler implements MessageQueue.IdleHandler { @Override public final boolean queueIdle() { doGcIfNeeded(); return false; } }
这是一个gc相关的IdleHandler,即如果没有更多的消息可以处理就会抽空doGcIfNeeded(),最后返回false表示不保留在mIdleHandlers
中,即用一次就扔了,只执行一遍。
参考文章:
http://www.cnblogs.com/kesalin/p/android_messagequeue.html
http://www.cnblogs.com/xiaoweiz/p/3674836.html