Handler、Looper、MessageQueue、Thread源码分析_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > Handler、Looper、MessageQueue、Thread源码分析

Handler、Looper、MessageQueue、Thread源码分析

 2015/4/6 18:48:07  John-Chen  程序员俱乐部  我要评论(0)
  • 摘要:关于这几个之间的关系以及源码分析的文章应该挺多的了,不过既然学习了,还是觉得整理下,印象更深刻点,嗯,如果有错误的地方欢迎反馈。转载请注明出处:http://www.cnblogs.com/John-Chen/p/4396268.html对应关系:1、Handler不带Looper的构造器/***Usethe{@linkLooper
  • 标签:thread Handler 源码 分析

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

  转载请注明出处: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

 

发表评论
用户名: 匿名