Handler、Looper、MessageQueue、Thread源码分析

  关于这几个之间的关系以及源码分析的文章应该挺多的了,不过既然学习了,还是觉得整理下,印象更深刻点,嗯,如果有错误的地方欢迎反馈。

  转载请注明出处:http://www.cnblogs.com/John-Chen/p/4396268.html

 

对应关系

  Handler、Looper、MessageQueue、Thread源码分析

 

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

 

你可能感兴趣的:(messagequeue)