Android Handler消息机制(源码解析)

Handler 的设计初衷 是为了解决 多线程状态下控件状态混乱问题,通过Handler 让主线程在更新UI控件的状态,而Handler 是面试中常被问起的问题,然后本文就带大家走一遍Handler 消息发送机制。

Handler 的三个属性(熟记)

public class Handler{

final Looper mLooper;

final MessageQueue mQueue;

final Callback mCallback;

......

}

01

通过Handler 的源码我们可以看到,Handler里面封装了一个Looper, 消息队列MessageQueue 和一个CallBack ,这个CallBack 是什么?别忘了我们在Handler初始化的时候通过构造器传入了一个匿名内部类:

public interface Callback {

public Handler boolean handleMessage(Message msg);

}

嗯,先在清楚了,就是我们常用的handleMessage,我们接着往下说。Android 中一个线程只能有一个Looper,而消息队列是Looper的内部属性:

public final class Looper {

private static final String TAG = "Looper";

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

private static Looper sMainLooper;  // guarded by Looper.class

final MessageQueue mQueue;

final Thread mThread;

02

那么Handler 中的成员属性Looper 和消息队列是怎么被初始化赋值的呢?

public Handler(Callback callback, boolean async) {

......

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can't create handler inside thread " + Thread.currentThread()

+ " that has not called Looper.prepare()");

}

mQueue = mLooper.mQueue;

mCallback = callback;

mAsynchronous = async;

}

看来这个问题也得到了解答,在Handler 构造器中已经完成了初始化,Handler 中的Looper 和消息队列 和 CallBack 都初始化了,Looper.myLooper() 会返回当前线程的Looper,那么问题来了,Handler 是如何把消息放入到消息队列的?在消息队列读出某个消息的时候又是怎样知道这个消息是来自哪个Handler实例?我们来看代码:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

msg.target = this;

if (mAsynchronous) {

msg.setAsynchronous(true);

}

return queue.enqueueMessage(msg, uptimeMillis);

}

通过源码追踪到Handler 不管是调用 post() 还是 sendMessage还是sendEmptyMessage还是SendMessageDelay 最终都会调上面这段代码,将消息放入队列,我们还看到msg.target = this;这就是将Handler 实例与消息关联了,这样Looper 中队列中取出消息就知道是哪个Handler发送过来的消息了,这样我们上面的两个问题就清楚了。

03

知道是哪个Handler 发送过来的消息,那么就要处理消息了,都是通过回调完成,有两种回调途径,第一种就是 handler 初始化的时候 传入了CallBack ,那么回调的时候,就回调 handleMessage(Message message) 方法。第二种事handler 发送过来的消息是通过post(Runnable runnable) 这种方式发的消息,那么消息回调 就是 通过  runnable.run()了,我们可以再看Message的源码:

public final class Message implements Parcelable {

Runnable callback;

......

看清楚了没,你通过 handler.post(Runnable  runnable)方法发的消息最终是回调这个Runnable 实例。

04

好了,到此为止我们的Handler 发送消息机制就讲完了,下面是在子线程中使用Handler 的方法:

Looper.prepare();

mHandler = new Handler(){

@Override

public void handleMessage(Message msg) {

Log.d(TAG," mHandler is coming");

handler_main.sendEmptyMessage(1);

}

};

mHandler.sendEmptyMessage(1);

Looper.loop();

loop()阻塞,后面的代码将不会执行。

(0)

相关推荐