Handler、Looper、MessageQueue、HanlderThread的详细解读

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的过程。

Handler、Looper、MessageQueue、HanlderThread的详细解读_第1张图片
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、HanlderThread的详细解读)