Android开发经验笔记Android进阶之旅android技术专栏

Handler、Looper、MessageQueue、Hanl

2017-01-19  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读