zoukankan      html  css  js  c++  java
  • Handler、Looper、MessageQueue、Thread源码分析

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

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

    对应关系

      

    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

  • 相关阅读:
    jsp页面跳转的路径问题
    Hibernate简单的保存操作
    Hibernate中如何完成持久化类和数据库映射文件
    spring中IOC的简单使用
    对称的二叉树 --剑指offer
    二叉树的下一个结点 --剑指offer
    删除链表中重复的结点 --剑指offer
    链表中环的入口结点 --剑指offer
    字符流中第一个不重复的字符 --剑指offer
    表示数值的字符串 --剑指offer
  • 原文地址:https://www.cnblogs.com/John-Chen/p/4396268.html
Copyright © 2011-2022 走看看