当前位置: 代码迷 >> Android >> Android Looper Hander跟MessageQueue的关系
  详细解决方案

Android Looper Hander跟MessageQueue的关系

热度:231   发布时间:2016-04-28 08:17:34.0
Android Looper Hander和MessageQueue的关系

? ? ? ?使用Handler和Thread是Android进行线程间通信的主要方式。具体方式是,在异步线程中,使用handler发送Message到指定队列(handler.sendMessage(Message msg))。目标队列接收消息后,将消息添加到队列中,Looper轮询队列,依次对异步线程发送过来的Message进行处理,下面结合Android源码详述。

? ? ? ?先看Handler的构造方法(android.os.Handler.java):

? ? ??

 public Handler() {           //doSomething          mLooper = Looper.myLooper();          if (mLooper == null) {            throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");          }        mQueue = mLooper.mQueue;        mCallback = null;    }    /**     * Constructor associates this handler with the queue for the     * current thread and takes a callback interface in which you can handle     * messages.     */    public Handler(Callback callback) {       //doSomething        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;    }    /**     * Use the provided queue instead of the default one.     */    public Handler(Looper looper) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = null;    }    /**     * Use the provided queue instead of the default one and take a callback     * interface in which to handle messages.     */    public Handler(Looper looper, Callback callback) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;    }

?每个handler必定有一个对应的Looper,如果没有在构造器中传入,则调用Looper.myLooper()生成一个默认的Looper,再去看Looper的代码(android.os.Looper.java):

 // sThreadLocal.get() will return null unless you've called prepare().    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();    /**     * Return the Looper object associated with the current thread.  Returns     * null if the calling thread is not associated with a Looper.     */    public static Looper myLooper() {        return sThreadLocal.get();    }

?sThreadLocal里什么时候装进去的Looper呢?在android.app.ActivityThread.java代码里发现了对Looper的static方法的调用:

 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);        Process.setArgV0("<pre-initialized>");        Looper.prepareMainLooper();        if (sMainThreadHandler == null) {            sMainThreadHandler = new Handler();        }        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

?这个main方法在系统启动时已经被调用过,android.os.Looper.sThreadLocal是一个静态常量,所有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      * [email protected] #loop()} after calling this method, and end it by calling      * [email protected] #quit()}.      */    public static void prepare() {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper());    }    /**     * 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: [email protected] #prepare()}     */    public static void prepareMainLooper() {        prepare();        setMainLooper(myLooper());        myLooper().mQueue.mQuitAllowed = false;    }    private synchronized static void setMainLooper(Looper looper) {        mMainLooper = looper;    }    /** Returns the application's main looper, which lives in the main thread of the application.     */    public synchronized static Looper getMainLooper() {        return mMainLooper;    }

?prepareMainLooper()方法调用了prepare()方法,prepare()方法为android.os.Looper.sThreadLocal进行赋值,我们继续跟进Looper的构造器:

    private Looper() {        mQueue = new MessageQueue();        mRun = true;        mThread = Thread.currentThread();    }

?至此,Looper和当前线程对应起来,并且实例化MessageQueue对象。

? ? ? ? ?按以上,如果我们在主线程里不传Looper实例化了一个Handler,handler对应的Looper所对应的线程就是ActivitThread运行的线程,就是我们常说的主线程。

? ? ? ? 如果我们在非主线程里实例化了一个Looper,方法必然是在当前线程调用Looper.prepare(); Looper.loop();。Handler对应的Looper对应当前线程。

? ? ? ? 一个线程中可以创建多个Handler,但只能拥有一个Looper,一个Looper对应一个消息队列。

? ? ? ? ?注:对同一个ThreadLocal对象调用get方法,不同线程将得到不同结果,具体原理与介绍不在此描述。

?

?

?

? ? ? 下面我们开始使用handler工作,发送消息时使用sendMessage方法或者Message的sendToTarget方法,最终都会调用到handler对应的Looper持有的MessageQueue,队列调用

final boolean enqueueMessage(Message msg, long when) {        if (msg.isInUse()) {            throw new AndroidRuntimeException(msg                    + " This message is already in use.");        }        if (msg.target == null && !mQuitAllowed) {            throw new RuntimeException("Main thread not allowed to quit");        }        final boolean needWake;        synchronized (this) {            if (mQuiting) {                RuntimeException e = new RuntimeException(                    msg.target + " sending message to a Handler on a dead thread");                Log.w("MessageQueue", e.getMessage(), e);                return false;            } else if (msg.target == null) {                mQuiting = true;            }            msg.when = when;            //Log.d("MessageQueue", "Enqueing: " + msg);            Message p = mMessages;            if (p == null || when == 0 || when < p.when) {                msg.next = p;                mMessages = msg;                needWake = mBlocked; // new head, might need to wake up            } else {                Message prev = null;                while (p != null && p.when <= when) {                    prev = p;                    p = p.next;                }                msg.next = prev.next;                prev.next = msg;                needWake = false; // still waiting on head, no need to wake up            }        }        if (needWake) {            nativeWake(mPtr);        }        return true;    }

?这个方法把发送的Message添加到队列中,而已经启动的Looper则一直在轮询运行

    /**     * Run the message queue in this thread. Be sure to call     * [email protected] #quit()} to end the loop.     */    public static void loop() {        Looper me = myLooper();        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        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();                while (true) {            Message msg = queue.next(); // might block            if (msg != null) {                if (msg.target == null) {                    // No target is a magic identifier for the quit message.                    return;                }                long wallStart = 0;                long threadStart = 0;                // This must be in a local variable, in case a UI event sets the logger                Printer logging = me.mLogging;                if (logging != null) {                    logging.println(">>>>> Dispatching to " + msg.target + " " +                            msg.callback + ": " + msg.what);                    wallStart = SystemClock.currentTimeMicro();                    threadStart = SystemClock.currentThreadTimeMicro();                }                msg.target.dispatchMessage(msg);                if (logging != null) {                    long wallTime = SystemClock.currentTimeMicro() - wallStart;                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);                    if (logging instanceof Profiler) {                        ((Profiler) logging).profile(msg, wallStart, wallTime,                                threadStart, threadTime);                    }                }                // Make sure that during the course of dispatching the                // identity of the thread wasn't corrupted.                final long newIdent = Binder.clearCallingIdentity();                if (ident != newIdent) {                    Log.wtf(TAG, "Thread identity changed from 0x"                            + Long.toHexString(ident) + " to 0x"                            + Long.toHexString(newIdent) + " while dispatching to "                            + msg.target.getClass().getName() + " "                            + msg.callback + " what=" + msg.what);                }                                msg.recycle();            }        }    }

?方法中msg.target.dispatchMessage(msg);说明handlder的dispatchMessage()方法运行在loop()调用的线程中,dispatchMessage方法将调用handleMessage方法。

? ? ?这样,Handler处理消息的代码将运行在其对应的Looper所在的线程。整体的结构也就清晰了:

? ? ?Handler实例化时,引用一个Looper,Looper唯一对应一个线程,Looper持有一个消息队列,Handler发送消息到消息队列,Looper轮询获取消息队列中的待处理Message,Message对象的target在轮询中顺次分发给Handler,Handler的handleMessage方法被调用。

  相关解决方案