Handler,Looper,Message,MessageQueue之间关系浅析

一、先看一下使用流程

1.在子线程中使用Handler实例

    /***********子线程使用Handler实例*********/
    private class LooperThread extends Thread
    {
        public Handler handler;
        @Override
        public void run()
        {
            Looper.prepare();
            handler = new Handler()
            {
                @Override
                public void handleMessage(Message msg)
                {        
                }
            };
            Looper.loop();
        }
    }

2、主线程(UI线程)中使用的Handler,Looper等
其实现在android/app/AcitvityThread.java文件中,如下:

public static void main(String[] args) {
        //前面一系列配置暂时不用关心
        SamplingProfilerIntegration.start();
        CloseGuard.setEnabled(false);
        Environment.initForCurrentUser();
        EventLogger.setReporter(new EventLoggingReporter());
        Security.addProvider(new AndroidKeyStoreProvider());
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
        Process.setArgV0("<pre-initialized>");
        /************从这里开始,使用Looper*******************/
        Looper.prepareMainLooper();//对比:子线程中使用Looper.prepare();
 
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
 
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();//对比:子线程中自创建new Handler()
        }
 
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
 
        Looper.loop();//对比:这里两者相同
 
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

二、查看源码:
(一)prepare()
1、看一下Looper.prepare()的源码:
    /** 将当前线程初始化为一个Looper.所以你可以在start loop前先创建Handlers,再引用这个looper;
      * 要确保在调用本方法后调用#loop()方法;结束本方法使用#quit();
      */
    public static void prepare() {
        prepare(true);         //对比:下面将会看到主线程中的prepareMainLooper中将会使用prepare(false)
    }
 
    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));
    }
附I)这里引出了一个sThreadLocal,首先看其定义:

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

    ThreadLocal类是个特殊的全局变量,其全局性只体现在自己的所在的线程(类名也体现出该特性),故因此每个线程的Looper都是独立的;
    ThreadLocal类Java本身已经给予实现,Android对其进行了实现优化;其主要思想仍为:ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本,Map中元素的键为线程对象,而值对应线程的变量副本
    前面源码中涉及到的get(),set(0方法分别为获取和设置当前线程所对应的线程局部变量值。

2、对比看一下prepareMainLooper():
   /**
     * 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) {
                thrownew IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = 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();
    }
附II): sMainLooper的定义:

    private static Looper sMainLooper;

和前面大致相同,只是定义了一个sMainLooper,get sThreadLocal获得一个Looper,让sMainLooper指向它;

(二)Handler

1、Handler部分源码:

Handler众多构造函数:

    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback) {
        this(callback, false);
    }
 
    public Handler(Looper looper) {
        this(looper, null, false);
    }
 
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
 
    public Handler(boolean async) {
        this(null, async);
    }
 
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

   /****************重点看此构造函数*********************/
    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();//依然通过sThreadLocal获取到当前Thread的Looper实例,可见这里两者联系到一起
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;   //这里MessageQueue是Looper与Handler沟通的桥梁
        mCallback = callback;
        mAsynchronous = async;
    }
附I)mQueue的定义:final MessageQueue mQueue;

可见通过MessageQueue,Handler与Looper联系到一起;

而观察源码可以发现Handler中常用的发送Message的方法如sendMessage等,最终的实现均是Message的enqueue操作,即进入MessageQueue队列。

(三)Looper.loop()处理事件流程

    public static void loop() {
        final Looper me = myLooper();//依然通过sThreadLocal获取到当前Thread的Looper实例
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;//获取到上面提到过的MessageQueue mQueue

        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        /****************循环处理消息*******************/
        for (;;) {
            Message msg = queue.next(); // 从MessageQueue中取出next消息
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                //表明当前MessageQueue正在退出
                return;
            }
 
            // 调试信息,跳过
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            /** 开始分派消息*/
            msg.target.dispatchMessage(msg);//Message中的定义Handler target,故dispatchMessage
                                            //最终调用Handler中的处理函数;
 
            /** 调试信息,跳过*/
            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }
            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();//回收处理完的消息Message
        }
    }
当Loop过程检测到有Msg时,会调用Msg的target即其对应的Handler中的dispatchMessage方法对Msg进行处理:
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // 可以看到这里最终调用重写的函数handleMessage对Message进行处理
        handleMessage(msg);
    }
}
可以看到具体的处理逻辑,如果Message的callback不为空的话,则调用handleCallback方法,即调用Message的callback(Runnable);
    private static void handleCallback(Message message) {
        message.callback.run();
    }
注意这里直接调用callback的run函数,也就是该事件的处理仍然在Handler所在的线程中。
Message设置callback的方法:
    // Message.java
    public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;
        return m;
    }
如果Message没有设置callback,则会接着判断Handler是否设置Callback;如果Handler设置了Callback则会优先处理callback再去处理handleMessage;
先来看Handler设置callback的方法:
// Handler.java
    public Handler(Callback callback) {
        this(callback, false);
    }

    public Handler(Callback callback, boolean async) {
        ......

        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;
        mAsynchronous = async;
    }
其实平时在使用handler去post一个Runnable的方法,就是通过设置callback来实现的:
    // Handler.java
    public final boolean post(Runnable r) {
        return  sendMessageDelayed(getPostMessage(r), 0);
    }

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

再看一下Looper的构造函数:
    private Looper(boolean quitAllowed) {          //构造函数是private的
            mQueue = new MessageQueue(quitAllowed);//MessageQueue是Looper创建时就被创建出来的
            mThread = Thread.currentThread();      //mThread为当前线程,即Looper与当前线程建立联系
    }
由上loop()方法可以简单得出结论,Looper用以处理MessageQueue中的取出的Message,由MessageQueue是Handler及Looper所共用的,取出的Message则交由Handler进行处理。而Handler也能够通过post或者send等方式将Message添加到MessageQueue中供Looper后续进行取出处理。sThreadLocal保证了Looper是线程私有的,所有信息发送与处理都是在本线程中。

    prepare()用以在sThreadLocal中创建线程与该线程对应的Looper的键值对;new Handler或者getHandler创建的Handler都根据sThreadLocal.get()进行获取;创建的Handler与Looper共用MessageQueue;loop开始循环处理Messagequeue中的事件。其即为整个流程。


面试题:
1、Handler消息机制
    根据ThreadLocal机制,每一个Thread对应一个Looper,创建的Looper类中包含有一个消息队列MessageQueue;Handler与Looper是一对一的对应关系,它可以通过post或者send操作将Message添加到MessageQueue中,因为它的内部有个对象指向MessageQueue。Looper通过perpare方法创建,调用loop开始对事件进行循环处理,它会检测MessageQueue是否有Message,如果存在,则调用Message对应的target的dispatchMessage方法进行处理;如果MessageQueue为空,则进行循环等待。

2、ThreadLocal机制:以线程为作用域,同一变量对于不同线程具有不同的数据副本。
      通过set/get函数来实现该线程对应的变量的赋值和获取值。
      原理:每一个Thread类中都有一个类型为Values的localValues变量,该变量中有一个Object类型的数据Object[] table,该数组奇数位用来存储ThreadLocal变量对应的key值,偶数位用来保存相对应的value值。通过set赋值,即是取出对应线程中的localValues变量,然后将键值对写入到table数组中;因此这样就保证了多个线程之间互不干扰地存储和修改数据。

3、MessageQueue的工作原理:
MessageQueue实际上是一个单链表,其主要执行消息入队列和出队列的操作;
enqueueMessage方法用来消息入队列,其操作实质上单链表的插入操作;
next方法用来消息出队列,当队列为空时,则会一直阻塞,循环等待;如果不为空,则将该消息从单链表中移除。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值