在android中handler机制中再常见不过了,用于异步处理,像项目中经常会在子线程中进行IO(网络 文件读写 数据库读写等)耗时操作,完成之后需要在UI线程进行界面更新,这种情况就需要用到Handler,来起到这种桥梁链接的作用。
OK,那我会问你,handler的内部机制是怎样?
答:handler会创建消息队列MessageQueue和Looper,当我们在子线程中发送sendMessage(Message msg)时,会加入到消息队列中,Looper会进行不断的消息循环,拿到加入的消息,进行dispatchMessage,进而会走到handler中的handlerMessage()方法中去,这样就切换到主线程了。
上面的回答完了,但其实是不严谨或者说内部很多细节没有讲到,换句话说就是对hanlder还了解的不够深入,例如随便问你几个问题,1.MessageQueue和Looper什么时候创建的。2.handler内部是如何获取到当前线程的Looper。3.MessageQueue存储消息是采用队列的形式来存储吗。4.如何在子线程中创建一个handler。
下面结合具体的源码来进行讲解。
1:MessageQueue和Looper创建的时机
这要从ActivityThread中的main()方法讲起,代码如下
1 public static void main(String[] args){
2 .....
3 //创建looper和messagerQueue
4 Looper.prepareMainLooper();
5
6 ActivityThread thread = new ActivityThread();
7 thread.attach(false, startSeq);
8 .....
9 if (false) {
10 Looper.myLooper().setMessageLogging(new
11 LogPrinter(Log.DEBUG, "ActivityThread"));
12 }
13 //开启消息循环
14 Looper.loop();
15}
可以这样理解在app应用启动的时候,就会创建looper和messageQueue,创建looper实例对象,同时MessagerQueue以成员变量的形式存在,同时会对looper进行设置ThreadLocal.set(looper),这个方法为后接下来的“handler内部如何获取到当前线程的Looper”提供了依据。
1.1 创建looper
1public static void prepareMainLooper() {
2 //准备创建looper
3 prepare(false);
4 synchronized (Looper.class) {
5 if (sMainLooper != null) {
6 throw new IllegalStateException("The main Looper has already been prepared.");
7 }
8 sMainLooper = myLooper();
9 }
10}
1.2 threadlocal设置looper
1private static void prepare(boolean quitAllowed) {
2 if (sThreadLocal.get() != null) {
3 throw new RuntimeException("Only one Looper may be created per thread");
4 }
5 //threadLocal设置looper
6 sThreadLocal.set(new Looper(quitAllowed));
7}
1.3 looper构造方法
1private Looper(boolean quitAllowed) {
2 //looper构造方法,创建messagerQueue
3 mQueue = new MessageQueue(quitAllowed);
4 mThread = Thread.currentThread();
5}
2. handler内部是如何获取到当前线程的Looper。
handler内部为什么需要获取looper呢,是因为hanlder.sendMessager(Messager)时需要拿到MessageQueue,把消息加入到队列中去。不同线程的handler如何拿到looper,是根据ThreadLocal为依据的,ThreadLocal并不是线程,它的作用是可以在每个线程中互不干扰地存储并提供数据,通过ThreadLocal可以轻松获取每个线程的looper。
当我们创建handler的时候,会走到如下的构造方法中去:
1public Handler(Callback callback, boolean async) {
2 ......
3 //拿到looper
4 mLooper = Looper.myLooper();
5 if (mLooper == null) {
6 //熟悉的代码,在子线程中创建handler,需要调用prepare()方法,否则报这个错误
7 throw new RuntimeException(
8 "Can't create handler inside thread that has not called Looper.prepare()");
9 }
10 //拿到looper对应的messageQueue
11 mQueue = mLooper.mQueue;
12 ........
13}
此时要进入到Looper.mylooper()方法内部才可以看到“真相”
1public static @Nullable Looper myLooper() {
2 //与之前的threadLocal.set(looper)遥相呼应
3 return sThreadLocal.get();
4}
至此handler内部就拿到了在ActivityThread中创建的looper(MessageQueue),从而可以进行sendMessager(),加入消息队列中去。
发送消息:
1public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
2 //通过looper拿到消息队列
3 MessageQueue queue = mQueue;
4 if (queue == null) {
5 RuntimeException e = new RuntimeException(
6 this + " sendMessageAtTime() called with no mQueue");
7 Log.w("Looper", e.getMessage(), e);
8 return false;
9 }
10 //加入消息队列
11 return enqueueMessage(queue, msg, uptimeMillis);
12}
加入消息队列:
1private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
2 //把handler的引用赋值给msg.target对象,为后期的MessagerQueue读消息,
3 //进行dispathMessager(),可以拿到对应的handler对象
4 msg.target = this;
5 if (mAsynchronous) {
6 msg.setAsynchronous(true);
7 }
8 return queue.enqueueMessage(msg, uptimeMillis);
9}
3. MessageQueue存储消息是采用队列的形式来存储吗。
答案:不是。MessagerQueue是采用单链表来存储的。
单链表形式来存储你加入的消息队列
1boolean enqueueMessage(Message msg, long when) {
2 ......
3 msg.markInUse();
4 msg.when = when;
5 Message p = mMessages;
6 boolean needWake;
7 if (p == null || when == 0 || when < p.when) {
8 // New head, wake up the event queue if blocked.
9 msg.next = p;
10 mMessages = msg;
11 needWake = mBlocked;
12 } else {
13 .......
14 needWake = mBlocked && p.target == null && msg.isAsynchronous();
15 Message prev;
16 for (;;) {
17 prev = p;
18 p = p.next;
19 if (p == null || when < p.when) {
20 break;
21 }
22 if (needWake && p.isAsynchronous()) {
23 needWake = false;
24 }
25 }
26 msg.next = p; // invariant: p == prev.next
27 prev.next = msg;
28 }
29
30 // We can assume mPtr != 0 because mQuitting is false.
31 if (needWake) {
32 nativeWake(mPtr);
33 }
34 }
35 return true;
36}
next()方法会返回这条消息并将其从单链表中删除。
1Message next() {
2 .......
3 for (;;) {
4 ......
5 synchronized (this) {
6 ......
7 Message prevMsg = null;
8 Message msg = mMessages;
9 if (msg != null && msg.target == null) {
10 // Stalled by a barrier. Find the next asynchronous message in the queue.
11 do {
12 prevMsg = msg;
13 msg = msg.next;
14 } while (msg != null && !msg.isAsynchronous());
15 }
16 if (msg != null) {
17 if (now < msg.when) {
18 // Next message is not ready. Set a timeout to wake up when it is ready.
19 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
20 } else {
21 // Got a message.
22 mBlocked = false;
23 if (prevMsg != null) {
24 prevMsg.next = msg.next;
25 } else {
26 mMessages = msg.next;
27 }
28 msg.next = null;
29 if (DEBUG) Log.v(TAG, "Returning message: " + msg);
30 msg.markInUse();
31 return msg;
32 }
33 }
34 }
35 }
36}
next()什么时候会被调用呢,在loop()中会一直被调用,不断的进行循环。
1public static void loop() {
2 //通过threadLocal拿到looper
3 final Looper me = myLooper();
4 if (me == null) {
5 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
6 }
7 //通过looper拿到消息队列
8 final MessageQueue queue = me.mQueue;
9 .......
10 for (;;) {
11 Message msg = queue.next(); // might block
12 if (msg == null) {
13 // No message indicates that the message queue is quitting.
14 return;
15 }
16 .......
17 try {
18 //msg.target即为handler,进入到handler.dispathMessager(msg)方法中去
19 msg.target.dispatchMessage(msg);
20 end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
21 } finally {
22 if (traceTag != 0) {
23 Trace.traceEnd(traceTag);
24 }
25 }
26 .........
27 }
28}
执行handleMessager(msg)方法
1public void dispatchMessage(Message msg) {
2 if (msg.callback != null) {
3 //设置了callback
4 handleCallback(msg);
5 } else {
6 if (mCallback != null) {
7 if (mCallback.handleMessage(msg)) {
8 return;
9 }
10 }
11 //走入到我们常见的handleMessage(msg)方法中去了
12 handleMessage(msg);
13 }
14}
4.如何在子线程中创建一个handler。
思考:为什么在主线程中创建handler不需要Looper.prepare()和Looper.loop()。
1public void createHandlerInThread(){
2 new Thread("Thread#2"){
3 @Override
4 public void run() {
5 //在子线程需要通过该方法手动创建looper和messageQueue
6 Looper.prepare();
7 Handler handler = new Handler(){
8 @Override
9 public void handleMessage(Message msg) {
10 super.handleMessage(msg);
11 }
12 };
13 //开启消息循环
14 Looper.loop();
15 }
16 };
17}
答案在ActivityThread类中main()方法中。
最后附上一张整体流程图: