Handler、Looper、MessageQueue、Hanl

作者: 陈利健 | 来源:发表于2017-01-19 11:20 被阅读239次

    1. 创建Handler对象需要Looper:

    在主线程中可以直接创建Handler对象,而在子线程中需要先调用Looper.prepare()才能创建Handler对象。
    看源码:Handler的无参构造函数中有这样一个判断:

        mLooper = Looper.myLooper();  
            if (mLooper == null) {  
                throw new RuntimeException(  
                    "Can't create handler inside thread that has not called Looper.prepare()");  
            }  
       mQueue = mLooper.mQueue; 
    

    显然,构造Handler对象,必须保证所在线程中存在一个Looper对象,同时依靠looper得到MessageQueue对象。
    在主线程中,本身就含有Looper对象,因为在程序启动的时候,已经自动调用了Looper.prepare()方法。

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

    Looper的prepare方法的作用就是判断sThreadLocal中是否已经存在Looper了,如果还没有则创建一个新的Looper设置进去。

    2. Looper的作用:

    Looper类用来为一个线程开启一个消息循环。

    1. 默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,并开启消息循环Looper.loop()
      Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,MessageQueue是在Looper的构造函数中创建的,因此一个Looper对应一个MessageQueue。

    2. 通常是通过Handler对象来与Looper进行交互的。Handler向指定的Looper发送消息。
      默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。
      new Handler() 等价于 new Handler(Looper.myLooper())。

    3. Looper.myLooper(): 用户获取当前进程的looper对象。
      Looper.getMainLooper(): 用于获取主线程的Looper对象。
      Looper.loop(): 让Looper开始工作,从消息队列里取消息,处理消息。

    注意:写在Looper.loop()之后的代码不会被执行,这个函数内部是一个死循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

    3. 线程间发消息:

    不论Handler对象在哪个线程中发出消息,最终消息都会回到创建Handler对象的那个线程中取处理。

    4. 消息传递机制

    Hnadler从sendMessge到handleMessage的过程。

    clipboard.png
    1. Handler调用自身的sendMessageAtTime(Message msg, long uptimeMillis)方法,msg被放入MessageQueue对象中去。

    2. MessageQueue调用其自身的enqueMessage()方法,将所有放入的Message对象按时间排序。方法内部主要过程有:msg.when表示该条Messge的入队时间,msg.next表示下一条准备出队的Message。

    3. Looper调用自身的loop()方法,依次将MessageQueue中的Message取出。MessageQueue的next()方法,就是消息队列的出队方法。

      public static final void loop() {
      Looper me = myLooper();
      MessageQueue queue = me.mQueue;
      while (true) { // 一个死循环
      Message msg = queue.next(); // might block
      if (msg != null) {
      if (msg.target == null) {
      return;
      }
      msg.target.dispatchMessage(msg); // 处理消息
      msg.recycle();
      }
      }

    1. 每当有一个消息出队,就将它传递到msg.target(就是发这条Message的Handler)的dispatchMessage()方法中。如果mCallback不为空,则调用mCallback的handleMessage()方法,否则直接调用Handler的handleMessage()方法,并将消息对象作为参数传递过去。

      public void dispatchMessage(Message msg) {
      if (msg.callback != null) {
      handleCallback(msg);
      } else {
      if (mCallback != null) {
      if (mCallback.handleMessage(msg)) {
      return;
      }
      }
      handleMessage(msg); // 回到handler自身的handleMessage方法
      }

    5. 最终由谁处理消息?

    在Looper的loop()方法中,取出从MessageQueue中取出下一位Message之后,就进入了处理消息阶段。

    public static final void loop() {  
        Looper me = myLooper();  
        MessageQueue queue = me.mQueue;  
        while (true) {
            Message msg = queue.next(); 
            if (msg != null) {  
                if (msg.target == null) {  
                    return;  
                }   
                msg.target.dispatchMessage(msg);
                msg.recycle();  
            }  
        }
    }    
    

    msg.target是谁?

    回到最开始的Handler的sendMessage方法:

    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");  
        }  
        return sent;  
    }  
    

    再来看看Message类的属性:

    public final class Message implements Parcelable {  
        public int what;  
        public int arg1;   
        public int arg2;  
        public Object obj;  
        int flags;  
        long when;  
        Bundle data;  
        Handler target;         // target处理  
        Runnable callback;      // Runnable类型的callback  
        // sometimes we store linked lists of these things  
        Message next;           // 下一条消息,消息队列是链式存储的  
        // 代码省略 ....  
    } 
    

    所以,msg.target就是发送这条msg的Handler对象。
    这就是“不论Handler对象在哪个线程中发出消息,最终消息都会回到创建Handler对象的那个线程中取处理。”的原理。饶了一圈,最终处理消息的还是这条MessageHandler对象,然后调用自身的dispatchMessage(msg)方法,消息对象作为这个其参数。

    6. 处理消息的方式有几种?

    深入看一下消息的最终处理方式:Handler的dispatchMessage(msg)方法。

    public void handleMessage(Message msg) {  
    }  
    
    private final void handleCallback(Message message) {  
        message.callback.run();  
    }  
    
    public void dispatchMessage(Message msg) {  
        if (msg.callback != null) {  
            handleCallback(msg);   // 设置了callback,调用callback(Runnable)的run方法
        } else {  
            if (mCallback != null) {  
                if (mCallback.handleMessage(msg)) {  
                    return;  
                }  
            }  
            handleMessage(msg);   // 没有设置callback,直接调用handleMessage
        }  
    }
    

    Message类的属性中可知,msg.callback指的是一个Runnable对象。

    Handler分发消息有两种情况,一种情况是直接sendMessage,这种情况不会设置callback。另一种情况是诸如post(Runnable r)postDelayed(Runnable r, long l)等方法,这种情况会设置callback。

    public final boolean post(Runnable r)  {  
       return  sendMessageDelayed(getPostMessage(r), 0);  
    }  
    
    private final Message getPostMessage(Runnable r) {  
        Message m = Message.obtain();  
        m.callback = r;  
        return m;  
    }  
    
    public final boolean sendMessageDelayed(Message msg, long delayMillis)  {  
        if (delayMillis < 0) {  
            delayMillis = 0;  
        }  
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
    } 
    

    post()的使用场景举例:

    Handler handler = new Handler();  
            new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    handler.post(new Runnable() {  
                        @Override  
                        public void run() { 
    
                        }  
                    });  
                }  
            }).start(); 
    

    另外,View的post()方法, Activity的runOnUiThread()方法,均是对Handler的post()方法进行了包装。

    7. 总结:Handler、Looper、MessageQueue分别存在于哪里,如何相互工作?

    Handler的创建必须保证其所在线程有且只有一个Looper对象的存在。Looper构造的时候,MessageQueue会随之一同创建。一个线程中可以有多个Handler的存在,但与之对应的线程、Looper和MessageQueue只有一个。

    随后,Handler对象不论在哪个线程中发Message,都会被与之对应的MessageQueue存放到自身队列当中去。并且根据所发送的Message的target属性,标记发送这条Message从属于哪个Handler。

    随后,通过Looper和MessageQueue的按时间先后依次取出Message后,再根据Message的target属性,识别这条Message是哪个Handler发送的,交由这个Handle回到创建时候的线程中去处理这个Message。

    8. 引申类:HandlerThread

    • 构造:
      HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它在执行run()方法的时候,会自动创建Looper对象,并持有其作为自己的一个成员变量。

      @Override
      public void run() {
      
        mTid = Process.myTid();
        Looper.prepare();
      
        synchronized (this) {
           mLooper = Looper.myLooper();
           notifyAll();
        }
      
       Process.setThreadPriority(mPriority);
       onLooperPrepared();
       Looper.loop();
       mTid = -1;
      
      }
      
    • 用途:
      Handler最终处理消息所在的线程是一开始创建这个Handler的所在的线程。假如这个处理消息过程是一个耗时的过程,那么放在主线程中是不合适的。HandlerThread的作用是让耗时工作在这个线程中处理。

    • 用法:

      private HandlerThread handlerThread;
      private Handler handler;
      
      @Override
      public void onCreate() {
       super.onCreate();
      
       handlerThread = new HandlerThread("test");
       handlerThread.start();
      
       handler = new Handler(handlerThread.getLooper()) {
         @Override
         public void handleMessage(Message msg) {
          super.handleMessage(msg);
      
         // 耗时操作,代码省略 ....
      
         handler1.sendEmptyMessageDelayed(0x01, updateTime1);
        }
      };
      
       handler.sendEmptyMessage(0x01);
      }
      
      @Override
      public void onDestroy() {
       super.onDestroy();
       handlerThread.quit();
      }

    相关文章

      网友评论

      本文标题:Handler、Looper、MessageQueue、Hanl

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