android Looper、Handler和MessageQueue关系

  android 消息框架可以在线程间传递消息,android中最广泛的应用场景就是子线程向UI线程发送更新UI的消息。
 Looper:用来进行消息循环,不停的从MessageQueue中取消息。
 Handler:向MessageQueue发送消息,并处理Looper传递来的消息。
 Message:消息载体。
 MessageQueue:消息队列的持有者,消息并不是直接存放到MessageQueue。
这是一个比较典型的应用事例。
 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();
        }
    }


下面我们围绕这个事例分析一下:
   线程首先调用了 Looper.prepare()方法,prepare()内部调用了带有参数的prepare(boolean)方法,参数主要是控制消息队列的特殊情况(队列中无消息时该如何处理);参数为true且无消息时,退出消息队列;参数为false且无消息时,消息队列进入阻塞状态,仅当消息队列有消息时,消息队列会被唤醒。
   其中sThreadLocal变量是ThreadLocal类型,ThreadLocal主要功能是保存线程本地变量;它类似于HashMap,以键值对的方式存储,键为当前线程。想详细了解的话可以看看这篇博文http://www.cnblogs.com/dolphin0520/p/3920407.html

 public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
   从上方法得出,一个线程只允许创建一个Looper,Looper创建完毕后就可以从MessageQueue取消息了;Looper.loop()后就进入消息循环了。
下面的方法主要是从消息队列取消息,然后处理消息;消息的最终消费者是Handler。

 public static void loop() {
        final Looper me = myLooper();
        if (me == null) { //没有创建Looper
            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(); // 可能会阻塞
            if (msg == null) {
                //没有消息时,表示消息队列正准备退出
                return;
            }

            // 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);
            }
           // 处理消息
            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // 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.recycleUnchecked();
        }
    }


那么消息时如何传递到相应的Handler呢?
  当我们调用Handler.sendMessage(Message)时,Message对象会保存Handler对象到target中;处理信息时调用target的dispathMessage()方法,最终会执行Handler的handleMessage()方法。
 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }



那么消息时如何传递到相应的Handler呢?
当我们调用Handler.sendMessage(Message)时,Message对象会保存Handler对象到自身,当要处理信息时,便从自身取出Handler
posted @ 2016-09-01 16:36  清澈见底  阅读(170)  评论(0编辑  收藏  举报