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

时间: 2024-10-13 01:08:44

Handler、Looper、MessageQueue、Thread源码分析的相关文章

Android异步消息处理 Handler Looper Message关系源码分析

# 标签: 读博客 对于Handler Looper Message 之前一直只是知道理论,知其然不知所以然,看了hongyang大神的源码分析,写个总结帖. 一.概念.. Handler . Looper .Message 这三者都与Android异步消息处理线程相关的概念. 异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环.若消息队列为空,线程则会阻塞等待. 说了这一堆,那么和Handle

Handler作用及部分源码分析

转载请注明出处,Lee:http://blog.csdn.net/hnulwt/article/details/44457905 Handler有俩个主要作用: 1,to schedule messages and runnables to be executed as some point in the future.在未来的某个时候去调度messages或者要执行的runnables. 2, to enqueue an action to be performed on a differen

Java Thread源码分析

1.Runnable接口源码: 1 public interface Runnable { 2 public abstract void run(); 3 } 2.Thread类与Runnable接口的继承关系 1 public class Thread implements Runnable{ 2 3 } Runnable接口仅有一个run()方法,Thread类实现了Runnable接口,所以,Thread类也实现了Runnable接口. 3.构造函数 1 public Thread() {

java Thread源码分析(二)

一.sleep的使用 1 public class ThreadTest { 2 public static void main(String[] args) throws InterruptedException { 3 Object obj = new Object(); 4 MyThread mt = new MyThread(obj); 5 mt.start(); 6 MyThread mt2 = new MyThread(obj); 7 mt2.start(); 8 } 9 priva

Android开发学习之路-Handler消息派发机制源码分析

注:这里只是说一下sendmessage的一个过程,post就类似的 如果我们需要发送消息,会调用sendMessage方法 public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } 这个方法会调用如下的这个方法 public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMilli

Android消息机制Handler、Looper、MessageQueue源码分析

1. Handler Looper MessageQueue的关系 2.源码分析 下图表示了Handler.Looper.MessageQueue.Message这四个类之间的关系. Handler必须与一个Looper关联,相关Looper决定了该Handler会向哪个MessageQueue发送Message 每一个Looper中都包含一个MessageQueue Handler中的mQueue引用的就是与之关联的Looper的MessageQueue 不管Handler在哪个线程发送Mes

Android -- 消息处理机制源码分析(Looper,Handler,Message)

android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因此我没将其作为核心类.下面一一介绍: Looper Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程.所谓Looper线程就是循环工作的线程.在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Lo

【Android】Handler、Looper源码分析

一.前言 源码分析使用的版本是 4.4.2_r1. Handler和Looper的入门知识以及讲解可以参考我的另外一篇博客:Android Handler机制 简单而言:Handler和Looper是对某一个线程实现消息机制的重要组成部分,另外两个重要元素是Message和MessageQueue,通过这四个类,可以让某个线程具备接收.处理消息的能力. 二.源码剖析 虽然只有四个类,而且这里只是剖析其中两个,但是也不能独立分析,必须组合进行解析.切入点是类Looper的注释中的一段示例代码: 1

[Android] 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析

1.Handler的由来 当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程. Android的UI操作并不是线程安全的(出于性能优化考虑),意味着如果多个线程并发操作UI线程,可能导致线程安全问题. 为了解决Android应用多线程问题-Android平台只允许UI线程修改Activity里的UI组建,就会导致新启动的线程无法改变界面组建的属性值. 简单的说:当主线程队列处理一个消息超过5秒,android 就会抛