美文网首页
Handler,MessageQueue,Runnable与Lo

Handler,MessageQueue,Runnable与Lo

作者: 小庄bb | 来源:发表于2018-07-25 15:05 被阅读14次

    前言

    什么叫又熟悉又陌生,这些概念就是了。对于这些概念相信没有人没见过,但是又没有几个人真正熟悉,所以就一直朦朦胧胧恍恍惚惚凄凄惨惨戚戚。今天就来解决这些恩恩怨怨,做个了断。

    概念初探

    Runnable,Message,MessageQueue,Looper和Handler的关系简图.png

    上面是Runnable,Message,MessageQueue,Looper和Handler的关系简图。其中:

    • Runnable和Message可以被压入某个MsaageQueue中,形成一个集合。注意:一般情况下某种类型的MsaageQueue只允许保存相同类型的Object。上图中我们只是为了方便叙述才把它们混放在MessageQueue中,实际源码中需要先对Runnable进行相应转换。
    • Looper循环地去做某件事
      它不断地从MessageQueue中取出一个item,然后传给Handler进行处理。如此循环往复,假如队列为空,那么它会进入休眠。
    • Handle是真正“处理事情"的地方
      它利用自身的处理机制,对传入的各种Object进行相应的处理并产生最终结果。
      用一句话来概括它们,就是:
      Looper不断获取MessageQueue中的一个Message,然后由Handle来处理。

    1. Handler

    不知道有没有人注意过,Handle和线程Thread是什么关系。

    public class Handler {...
            final MessageQueue mQueue;
            final Looper mLooper;
            final Callback mCallback;
    }
    

    从Handler的源码中看不出与Thread有什么关系,但其实:

    1. 每个Thread只对应一个Looper;
    2. 每个 Looper只对应一个MessageQueue;
    3. 每个MessageQueue中有N个Message;
    4. 每个Message中最多指定一个Handler来处理事件。
      5.一个Thread可以对应多个Handler。

    Handler是应用开发人员经常会使用到的一个类,它有两个方面的作用。

    • 处理Message,这是它作为"处理者"的本职所在。
    • 将某个Message压入MessageQueue中。
    #实现第一个功能的相应函数
    public void dispatchMessage (Message msg); //对Message进行分发
    public void handleMessage(Message msg); //对Message进行处理
    

    Looper从MessageQueue中取出一个Message后,首先使用调用dispatchMessage进行消息派发;后者则根据具体的策略来将Message分发给相应的负责人。默认情况下Handler的派发历程是:

    Message.callback(Runnable 对象)是否为空
    在不为空的情况下,将优先通过callback来处理
    Handler.mCallback是否为空
    在不为空的情况下,调用mCallback.handleMessage
    如果前两个对象都不存在,才调用Handler.handleMessage

    由此可见,Handler的扩展子类可以通过重载dispatchMessage或者HandleMessage来改变它的默认行为。

    Handler的第二个功能,容易引起开发人员的疑惑,因为这样形成了Handler->MessageQueue->Message->Handler的循环。

    #实现第二个功能的主要方法
    1. post系列
    final boolean post (Runnable r);
    final boolean postAtTime(Runnable r, long uptimeMills);
    2. Send系列
    final boolean sendEmptyMessage(int what);
    final boolean sendMessageAtFrontOfQueue(Message msg);
    boolean sendMessageAtTime(Message msg, long uptimeMillis);
    

    Post和Send的作用都是将某一个消息压入MessageQueue中,区别在于后者处理的参数直接就是Message,而Post需要先将零散的信息转换成Message,再调用Send系列函数来执行下一步。

    #post方法内部
    public final boolean post(Runable r){
            return sendMessageDelayed(getPostMessage(r), 0);
    }
    
    private static Message getPostMessage(Runnable r){
            Meaage m = Message.obtain();
            /*
              Android系统会维护一个全局的Message池。当用户需要时可以通过obtain函数获得,避免产生不必要的资源浪费。
             */
            m.callback = r;/*将Runnable对象设置为Message的回调函数*/
            return m;
    }
    

    有上述源代码可以看出,post实质上是根据传入的信息,从Mseeage池中获得一个Message并将Runbale设置为Message的回调函数。最后还是使用send函数将Message添加到MessageQueue。

    2. MessageQueue

    MessageQueue是一个消息队列,因而它具有队列的所有常规操作,包括:

    • 新建队列
      由其构造函数和本地方法nativeInit组成。其中nativeInit会在本地创建一个NativeMessageQueue对象,然后直接赋值给MessageQueue中的成员变量。这一系列操作实际都是通过内存指针进行的。
    • 元素入队
      final boolean enqueueMessage(Message msg, long when)
    • 元素出队
      final Message next()
    • 删除元素
      final void removeMessage(Handle h, int what, Object object)
      final void removeMessage(Handler h, Runnable r, Object object)
    • 销毁队列
      和创建过程一样,还是通过本地的NativeDestory来销毁一个MessageQueue。

    3. Looper

    Looper有点类似于发动机,它的推动使得整个Handler机制成为活源之水,不断的处理新的消息。Looper的使用有两种情况,即在主线程以及在工作线程。

    #工作线程的使用Looper的范例。
    class LooperThread extend Thread{
            public Handler mHandler; 
            public void run() {
                  Looper.prepare();
                  mHandler = new Handler() {
                             public void handleMessage(Message msg){
                             //处理消息的方法
                             }        
        };
                  looper.loop();//进入主循环
      }
    }
    

    这段代码概括起来只有三个步骤:

    1. Looper的准备工作(prepare)
    2. 创建处理消息的Handler
    3. Looper开始运作(loop)
      我们可以看到使用的步骤十分简单,但是仍有一些地方十分模糊,例如:looper是如何创建的,loop是如何与handler还有MeaasgeQueue进行连接的。
      首先我们发现在上述调用中使用了Looper.prepare()函数,既然要用Looper类的函数,那么LooperThread中肯定就得import android.os.Looper;观察Looper类我们发现在Looper类里有一个很重要的成员
    static final ThreadLocal<Looper> sThreadLoal = new ThreadLocal <Looper> ();
    

    这是一个静态变量,这就意味着在引用Looper时,sThreadLocal时就已经存在并成功构建。ThreadLocal对象是一种特殊的全局变量,但是这种全局只局限与线程内,这就意味着每个线程的Looper都是独立的。Looper为我们提供了很多静态方法,可这毕竟是公共的方法,其内部还需要有针对每个Thread的特定存储空间。因而sThreadLocal肯定会创建一个只针对当前线程的Looper以及其他相关的对象,而且这个操作很可能在prepare()。

    private static void prepare(boolean quitAllowed){
          if(sThreadLocal.get() != null){
                  throw new RuntimeException("Only one Looper may be created per thread")
          }//这个判断保证一个线程中只有一个Looper实例。
          sThreadLocal.set(new Looper(quitAllowed));
    }
    

    由上述代码我们可以看出,sThreadLocal存储了一个Looper对象。
    接下来创建一个Handler对象,这个步骤看起来也是平淡无奇,就是使用Handler的构造函数创建一个实例。那么,Handler到底与Looper是如何连接起来的呢?没错就是构造函数。
    Handler有很多构造函数:

    public Handler();
    public Handler(Callback callback);
    public Handler(Looper looper);
    public Handler(Looper looper, Callback callback);
    

    之所以会有那么多参数,是因为Handler中有很多内部变量需要初始化

    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
    

    以第一个无参构造函数为例:

    public Handler(){
              /*省略部分代码*/
              mLooper = Looper.myLooper();//还是通过sThreadLocal.get()来获取当前线程中的实例。
              ... 
              mQueue = mLooper.mQueue;//mQueue是Looper与Handler之间沟通的桥梁
         mCallback = null;
    }
    

    这样Handler和Looper,MessageQueue就联系起来了。后续Handler执行Post/Send两个操作时,会将消息投递到mQueue也就是mLooper.mQueue中,一旦Looper处理到这一消息,它又会从中调出Handler进行处理。
    好了就剩下Looper.loop()了,这部分需要借助ActivityThread讲解。看到这里一定有一点累了,喝口小茶,歇息几分钟,下一篇再仔细说明。

    相关文章

      网友评论

          本文标题:Handler,MessageQueue,Runnable与Lo

          本文链接:https://www.haomeiwen.com/subject/hrnumftx.html