Handler机制详述2---Looper,MessageQueue

1. 为什么Android会设计Handler去更新UI

Handler根本上是为了解决多线程之间引发的并发问题,在ActivityThread中,要是有多个子线程在没有加锁的情况下更新UI,有可能引发UI显示错乱的现象,但要是对更新UI的操作进行类似synchronized加锁机制的话,会造成性能下降,而Handler允许多线程向一个MessageQueue中押入Message,在UIThread中通过轮询的方式取出Message,并进行对应的处理,这样就可以避免UI显示错乱的问题,又不会降低性能。

2.Handler的内部机制---Looper,MessageQueue

(1).Looper:在一个Handler对象被创建时,内部自动关联了一个Looper对象,而Looper的内部会包含一个消息队列(MessageQueue对象),所有的给该Handler对象发送的Message,都会被加入到这个MessageQueue,
在Looper被创建之后,会调用Looper.loop()方法,looper()方法内部开始了一个for(;;)的死循环,不断的从MessageQueue中读取消息,如果取到Message,则处理消息,没有消息则处于阻塞状态。

(2).MessageQueue,消息队列为存放消息的容器

首先,查看ActivityThread.java源码,在ActivityThread的main()方法中可以看到这么一行代码:

Looper.prepareMainLooper();

打开这个prepareMainLooper()方法,在Looper的源码中可以看到:

public static void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper());
        myLooper().mQueue.mQuitAllowed = false;
    }

而prepare()的源码:

public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }

可以看出,prepare()方法中,首先是从sThreadLocal中通过get()判断是否为null,若为null,则会new一个Looper对象,并存储在sThreadLocal中,查看new Looper()方法的源码:

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

在Looper()的构造函数中,会创建一个消息队列MessageQueue,并将mThread指定为Thread.currentThread(),即Handler被new的线程,当Handler在UIThread中创建的时候,该mThread就是UIThread,那么为何此处要获得是在那个Thread中创建该Handler呢,首先让我们看看ThreadLocal这个数据类型,ThreadLocal用于存放与线程相关的变量信息,我们可以看到在Looper()构造函数中有:

// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

此处创建了一个存放Looper的ThreadLocal对象,在上面的prepare()中可以看到,new出来的Looper()通过set()方法存放在ThreadLocal中,看看ThreadLocal的set()方法:

public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
    }

ThreadLocal的get()方法如下:

public T get() {
        // Optimized for the fast path.
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values != null) {
            Object[] table = values.table;
            int index = hash & values.mask;
            if (this.reference == table[index]) {
                return (T) table[index + 1];
            }
        } else {
            values = initializeValues(currentThread);
        }

        return (T) values.getAfterMiss(this);
    }

可以看得出来,ThreadLocal的set()方法中,存储变量value的values是通过currentThread唯一创建的,不同的Thread初始化获得的values不同,而ThreadLocal的get()方法中,也是首先通过currentThread获得currentThread对应的values,从而获得value,这样处理,是为了在不同的Thread中通过ThreadLocal获得相对于的已经存入T hreadLocal的变量信息,ThreadLocal就是为了在多线程的情况下,为不同的线程保存相同类型的,不同的数据对象。

从Looper()的构造函数中看到,MessageQueue是在Looper被创建的时候创建的,用于接收发送给对应Handler对象的Message对象。

下面看一下Handler被new创建的源码:

public Handler() {
        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();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = null;
    }

可以看到有两行重要的代码:

mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;

其中mLooper = Looper.myLooper()方法的源码:

/**
     * 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变量get()到的,而ThreadLocal的get方法会拿到currentThread对应的Looper对象,这就可以与前面的代码联系起来了。ActivityThread通过执行prepare()方法为UIThread唯一创建了Looper对象和接受Message的消息队列,并保存在了UIThread的ThreadLocal对象中,而在UIThread中创建Handler的时候,拿到的Looper正是之前ActivityThread中创建的Looper,而mQueue即是对应的消息队列,两处的Looper指向相同,两处的MessageQueue指向也相同。

Handler在被创建的时候拿到消息队列,便可以通过如handleMessage()方法向该消息队列中添加请求,而在ActivityThread创建Message Queue的时候,就已经在主线程中通过Looper.loop()的方法开启了一个for死循环来轮询Message,这样就把UIThread中的Looper和Handler相关联起来了,以后在子线程中调用 handler.sendMessage()方法的时候,其实质就是将Message加载到了UIThread的MessageQueue中,而在UIThread中已经有一个死循环轮询并在UIThread中处理Message了。

下面我们跟踪一下子线程中的handler.sendMessage(0x1)方法,一层层的最终到了boolean sendMessageAtTime(Message, long)方法:

public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }

从上面可以看到,sendMessage方法最终是在mQueue中通过enqueueMessage()方法,将Message压入到mQueue中。

下面看看Looper.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();
            }
        }
    }

值得注意的是,loop()中首先会通过myLooper()方法获得Looper对象,而此Looper对象,是在sThreadLocal中get到的,与Handler创建时的Looper对象一样,都指向了ActivityThread中创建的Looper对象,同样对应的MessageQueue也是同一个;在loop()方法中会通过一个for(;;)死循环通过mQueue.next()取得Message,当Message对象不为null,则通过msg.target.dispatchMessage(msg)去处理数据,否则处于阻塞状态。

[注意]其中msg.target为当前Message对应的Handler。

而Handler的dispatchMessage(Message)方法:

/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

根据情况分别调用mCallback.handleMessage(msg)方法和handleMessage(msg)方法。

[总结]

UIThread在被初始化创建的时候,会首先通过prepare()方法为当前线程创建一个Looper对象,并存储在当前线程的ThreadLocal中,Looper的创建,其内部会自动创建一个消息队列(MessageQueue)的对象mQueue,在UIThread中创建一个Handler对象uiHandler的时候,uiHandler会从当前线程(UIThread)的ThreadLocal中拿到Looper对象,从而获得ActivityThread为UIThread创建的MessageQueue对象mQueue,当子线程通过uiHandler发送Message的时候,会首先将Message的target指向当前的uiHandler,并将此Message对象压入到mQueue中,而在ActivityThread创建Looper成功之后,便会通过Looper.loop()方法以死循环的方式轮询mQueue中的消息,当获得一个不为null的Message对象时,就会将该Message发送给Message对应的target(target为Handler对象)处理,target回调我们自定义实现的Callback.handleMessage(msg)和handleMessage(msg)方法处理消息。

时间: 2024-10-06 23:29:16

Handler机制详述2---Looper,MessageQueue的相关文章

Handler机制详述1---Handler的简介和用法

1.Handler简介 handler是Android系统封装的用于线程更新UI,消息处理的机制. [说明] 查看Android Framework源码可以看到,常见的Activity的生命周期onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy()都是通过handler发送不同Message,AMS(Activity Manager Service)通过Handler向ActivityThread发送消息,在Acti

Android Handler处理机制 ( 三 ) ——Handler,Message,Looper,MessageQueue

在android中提供了一种异步回调机制Handler,使用它,我们可以在完成一个很长时间的任务后做出相应的通知 handler基本使用: 在主线程中,使用handler很简单,new一个Handler对象实现其handleMessage方法,在handleMessage中 提供收到消息后相应的处理方法即可,这里不对handler使用进行详细说明,在看本博文前,读者应该先掌握handler的基本使用,我这里主要深入描述handler的内部机制 .现在我们首先就有一个问题,我们使用myThread

Android Handler机制 (一个Thead中可以建立多个Hander,通过msg.target保证MessageQueue中的每个msg交由发送message的handler进行处理 ,但是 每个线程中最多只有一个Looper,肯定也就一个MessageQuque)

转载自http://blog.csdn.net/stonecao/article/details/6417364 在android中提供了一种异步回调机制Handler,使用它,我们可以在完成一个很长时间的任务后做出相应的通知 handler基本使用: 在主线程中,使用handler很简单,new一个Handler对象实现其handleMessage方法,在handleMessage中 提供收到消息后相应的处理方法即可,这里不对handler使用进行详细说明,在看本博文前,读者应该先掌握hand

Android中的Handler, Looper, MessageQueue和Thread

Android中的Handler, Looper, MessageQueue和Thread 前几天,和同事探讨了一下Android中的消息机制,探究了消息的发送和接收过程以及与线程之间的关系.虽然我们经常使用这些基础的东西,但对于其内部原理的了解,能使我们更加容易.合理地架构系统,并避免一些低级错误. 对于这部分的内容,将分成4小节来描述: 1.职责与关系 2.消息循环 3.线程与更新 4.几点小结 ------------------------------------------------

Handler+Looper+MessageQueue深入详解

概述:Android使用消息机制实现线程间的通信,线程通过Looper建立自己的消息循环,MessageQueue是FIFO的消息队列,Looper负责从MessageQueue中取出消息,并且分发到消息指定目标Handler对象.Handler对象绑定到线程的局部变量Looper,封装了发送消息和处理消息的接口. 例子:在介绍原理之前,我们先介绍Android线程通讯的一个例子,这个例子实现点击按钮之后从主线程发送消息”hello”到另外一个名为” CustomThread”的线程. Loop

理解Thread,Looper,MessageQueue,Handler关系

概括来说,Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制.我们在使用Handler的时候与Message打交道最多,Message是Hanlder机制向开发人员暴露出来的相关类,可以通过Message类完成大部分操作Handler的功能.但作为程序员,我不能只知道怎么用Handler,还要知道其内部如何实现的.Handler的内部实现主要涉及到如下几个类: Thread.MessageQueue和Looper.这几类之间的关系可以用如下的图来简单说明: Threa

线程间通信: Handler , Looper, MessageQueue, Message (完结)

概述:    为了 线程间 通信方便, Handler 机制 通过 Handler 和 Looper, MessageQueue, Message 这些 类 之间的协作, 简化 多线程的开发.  线程的交互 会被封装 到 Message 中, 然后 通过 Handler 的方法 把 消息 放到 MessageQueue 消息队列中, 实现 Handler 机制的线程 都会 调用 Looper 的 loop() 方法, 则 Looper 作为 消息分发者的 作用就体现出来了.  loop() 方法

Android异步处理三:Handler+Looper+MessageQueue深入详解

Android Loop&Handle学习总结 - New Start - 博客频道 - CSDN.NET ?????? 昨晚偷懒,这篇博客只写了一个标题,今天早晨一看,还有15的阅读量.实在是对不起那些同学.......换了是我,也会BS这样的LZ吧!sorry 啦 -------------------------------------------------------------------------------------------------------------------

Android 消息机制 (Handler、Message、Looper)

综合:http://blog.csdn.net/dadoneo/article/details/7667726 与 http://android.tgbus.com/Android/androidnews/201204/421642.shtml 一. 消息机制常用类的介绍和使用 在Android程序运行中,线程之间或者线程内部进行信息交互时经常会使用到消息,如果我们熟悉这些基础的东西及其内部的原理,将会使我们的Android开发变的容易.可以更好地架构系统.在学习Android消息机制之前,我们