一.Looper、Handler、MessageQueue与Message的关系与相关概念

1.什么是Android消息处理机制?

  “消息”是windows运行机制中一个基本而又重要的概念。消息是一个报告事件发生的通知,消息驱动是围绕消息的产生与处理展开的,并依靠消息循环机制来实现(百度百科)。与Windows系统一样,Android也是消息驱动型的系统。引用一下消息驱动机制的四要素:

1
2
3
4
5
6
7
  ①接收消息的“消息队列”

  ②阻塞式地从消息队列中接收消息并进行处理的“线程”

  ③可发送的“消息的格式”

  ④“消息发送函数”

与之对应,Android系统中对应实现了:

1
2
3
4
5
6
7
  ①接收消息的“消息队列” —— MessageQueue

  ②阻塞式地从消息队列中接收消息并进行处理的“线程” —— Thread+Looper

  ③可发送的“消息的格式” —— Message

  ④“消息发送函数”—— Handler的post()和sendMessage()

  Android有大量的消息驱动方式来进行交互,比如Android的四大组件——Activity, Service, Broadcast, ContentProvider的启动过程的交互,都离不开消息机制。

2.Handler

  Android的消息机制,很多时候我们也称之为“Handler机制”,可见Handler这个东西是相当重要了~~那么Handler是用来干什么的呢?刚刚笔者在刷知乎的时候看到有大神怼(教导)一个Android菜鸟的时候其中就提到了一点“…以为Handler就是用来更新UI的…”——好吧,真是垂死病中惊坐起——开始学Android那会笔者也曾经这么认为(捂脸)。

  如果你也这么认为,那么从今天起你就要放弃这种狭隘的想法——Handler是Android消息机制的上层接口,因此我们在开发中与Handler打交道的机会最多。Handler并不是专门用来更新UI的,只是开发者常常用它来更新UI。

Handler的主要用于同一个进程间的线程通信,Handler用于更新UI的时候是”子线程与主线程通信”;当然,Handler也可以用于子线程之间通信

  Handler的消息机制主要是就指“Handler的运行机制”,Handler的运行机制时需要底层的MessageQueue和Looper支持的。

3.MessageQueue

  MessageQueue翻译过来是”消息队列”的意思,实际上它内部的数据结构不是队列,而是单向链表;MessageQueue中储存了大量的消息,由于一个线程同一时间只能处理一条消息,所以我们建了一个链表,将我们需要处理的消息按顺序储存起来,然后一项一项的交给需要的线程处理,这就是MessageQueue存在的价值。

  这里笔者想到一个问题——为什么MessageQueue要用链表而不用数组来作为数据结构呢?再经过网上查找博客+源码阅读,笔者认为是这样的——之前我们在一片文章中有讲过,单链表更适合做增删的操作,数组更适合做随机访问的操作。再MessageQueue中,我们不止要做随机访问(这里不是真的随机访问,消息的读取是根据计算出来的时间顺序来的,后文会讲)跟多的我们做的是插入和删除操作,MessageQueue.enqueueMessage()就是插入消息(消息的插入需要根据时间发送的时间顺序来确定,不存在头插还是尾插),而插入消息;而MessageQueue.next()则是读取消息,且读取的同时也伴随这删除的过程。试想一下,一个消息队列要循环起来,必然要频繁的进行插入/读取操作,假如采用数组的话,这两个操作的平均时间复杂度都是O(N/2),而链表为O(1),显然链表更合适。

4.Looper

  Looper和MessageQueue的消息就像水泵和井(里边装的是水)的关系一样,我们有了消息(水),但是为了把水从井中抽取出来(循环起来),我们得有一个水泵作为动力,这个动力就是Looper。

  如果我们在一个线程中调用Looper.prepare()…Looper.loop(),那么你的线程就成功升级为了一个Looper线程,这意味着你的线程有了一个消息泵(Looper)和一个消息队列(MessageQueue),此时你就可以调用Handler来进行线程间的通信了。

  我们应用的UI线程也就是主线程,在应用启动的时候,系统会自动初始化一个Looper,也就是说,我们的UI线程默认是Looper线程。这也就是为什么主线程中直接调用Handler没什么事,但是再子线程中创建Handler需要哦手动调用Looper.prepare()…Looper.loop()的和原因。

5.Message

  Message也就是消息,井中的水。一个Message包括了消息类型(what),消息内容(arg1,arg2),发送它的Handler(target),Runnable回调接口等:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public int what;        //数据类型
public int arg1; //简单的整数值
public int arg2; //简单的整数值可以直接发送,是一种替代setData(Bundle)的低成本方案,更加省资源
public Object obj;
......
/*package*/ int flags;
/*package*/ long when; //Handler发送一个消息之后,返回此消息的目标交付时间(以毫秒为单位)。
/*package*/ Bundle data; //Bundle可以携带更复杂的数据类型
/*package*/ Handler target; //哪个Handler发送的消息
/*package*/ Runnable callback;
//可以看到,Message带了一个指向一下个节点的链,也就是说,MessageQueue内部维护的实际上是一个链表
/*package*/ Message next;
private static final Object sPoolSync = new Object();
private static Message sPool; //消息池
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50; //消息池的最大容量

讲到这里,我们先上一张图加深一下大家对于这几个东西的直观认识:

二.子线程与主线程Handler通信原理(子线程是如何通过Handler更新UI的)

1.一些熟悉的场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) { //判断标志位
case 1:
//更新UI操作
break;
}
}
};

public class MyThread extends Thread {
@Override
public void run() {
super.run();
//耗时操作

Message msg =Message.obtain();//从全局池中返回一个message实例,避免多次创建(如new Message)
msg.obj = data;
msg.what=1; //标志消息的标志
handler.sendMessage(msg);
}

new MyThread().start();

  上面代码是我们再Android开发中经常写的一段代码,其主要作用是再子线程中进行耗时操作,并通过Handler向主线程中发送消息,通知主线程做出相应的UI变化。注意这段代码中,Handler是再主线程中创建的,因此不需要手动调用Looper.prepare()添加Looper。

  如果我们试图再子线程中创建一个Handler,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Handler handler ;
public class MyThread extends Thread {
@Override
public void run() {
super.run();
//耗时操作

handler = new Handler();
Message msg =Message.obtain();//从全局池中返回一个message实例,避免多次创建(如new Message)
msg.obj = data;
msg.what=1; //标志消息的标志
handler.sendMessage(msg);
}
new MyThread().start();

那么很显然,这个时候就会出bug了~~为了解决这个bug,我们需要手动再子线程中创建Looper:

1
2
3
4
5
6
7
handler = new Handler();
Looper.prepare();
Message msg =Message.obtain();//从全局池中返回一个message实例,避免多次创建(如new Message)
msg.obj = data;
msg.what=1; //标志消息的标志
handler.sendMessage(msg);
Looper.loop();

为什么是这样呢?接下来从源码的解读分析

2.Looper

(frameworks/base/core/java/android/os/Looper)

(1)Looper.perpare()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public final class Looper {
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
......
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
}

首先我们看到Looper.prepare()方法中调用了prepare(ture)方法,其中true表示,该Looper是可以被终止的。因为我们是在子线程中创建的Looper,当子线程的消息处理完之后,理应把改Looper终止掉(MessageQueue.quit)。但是在主线程的Looper中:

1
2
3
4
public static void prepareMainLooper() {
prepare(false);
......
}

prepareMainLooper就是给主线程添加Looper,可以看到,主线程中的prepare(false)中的参数false表示的是,主线程中的Looper不能被终止掉,毕竟它是整个应用的生命,需要时刻准备着处理或者正在处理应用中的各种消息。

  好了我们接着看上面的prepare()中干了什么。这里出现了一个新的重量级的东西:sThreadLocal,它是ThreadLocal类的实例,关于ThreadLocal类是干什么的,我们在这里不做过多解释,我们只需要知道他是用于储存不同线程唯一对象的一个东西,即多个线程在ThreadLocal类中,通过ThreadLocal.set()保存了自己的变量之后,那么我们再各个子线程中调用ThreadLocal.get()方法,得到的仍然是当前线程之前存进去的那个值。各个线程存取各自的值,不会产生冲突。

  知道了ThreadLocal的作用之后,我们在来看sThreadLocal.set(new Looper(quitAllowed));这句表示我们再ThreadLocal类中保存了一个Looper对象(new Looper()),根据上面对ThreadLocal类的介绍,如果我们再当前线程中调用ThreadLocal.get()方法,则会得到本线程之前保存的唯一的变量。因此:

1
2
3
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}

这个if表示的是,如果sThreadLocal.get() != null,说明当前线程中已经存在一个Looper,我们不能在一个线程中同时创建多个,所以此时会抛出异常。为了避免这种异常,我们可以在Looper.prepare()之前调用Looper.myLooper()类来返回当前线程中的Looper对象,判断为空之后,再调用prepare():

1
2
3
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}

  Ok,比比了这么多,我们接着看new Looper()中Looper中的构造函数中做了什么:

1
2
3
4
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

这里出现了消息队列MessageQueue(quitAllowed),其中参数就是表示是否允许Looper退出的标示符。可以看到,在Looper中我们创建了一个MessageQueue实例:

1
2
3
4
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}

,此时我们的Looper就拥有了MessageQueue的对象引用。

(2)Looper.Loop()

  在Looper.perpare()调用完即我们为线程准备好Looper之后,最后一步我们还需要调用Loop()让整个Looper循环起来,这样消息才能发送出去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
......
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
......
msg.target.dispatchMessage(msg);
......
msg.recycleUnchecked(); //释放占据的资源
}
}

首先调用了我们刚说过的myLooper()来获取当前线程再ThreadLcoal类中储存的Looper,如果Looper为空则会抛出异常,提示当前线程没有Looper。然后inal MessageQueue queue = me.mQueue;是获取当前线程的Looper中的MessageQueue对象。

  之后这个Looper便进入了一个无限循环的状态——for(;;),Message msg = queue.next();是一条一条遍历整个消息队列,拿出msg消息。

  而msg.target.dispatchMessage(msg);这句中的msg.target实际上就是当前消息的目标Handler,也就是哪个线程中的Handler发送的消息,当然,这个发送它的Handler也要在自己所在的线程中接受这条消息。

  msg.recycleUnchecked();这句是将这天消息放入Message类中的消息池中。

从上面我们基本上可以得出——Looper > MessageQueue > Message的关系,也就是说,每个Looper中维护了一个消息队列,而一个消息队列中则以链表的形式排列着一条条消息。

3.MessageQueue.next()

(frameworks/base/core/java/android/os/MessageQueue)
上面的Looper类中我们实例化了一个MessageQueue对象,并调用了MessageQueue.next()类方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Message next() {
final long ptr = mPtr; //当消息循环已经退出,则直接返回
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration 循环迭代的首次为-1,也就是初始值为-1
int nextPollTimeoutMillis = 0;
for (;;) { //消息队列开始无限循环
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//阻塞操作的方法,当等待nextPollTimeoutMillis时长,或者消息队列里边有了消息被唤醒时,
//只有满足这两个条件该方法才会返回,for循环才能往下执行下面的代码,否则就一直在这等着
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) { //这一段同步块代码中就是再检索下一条message,如果找到了就返回
final long now = SystemClock.uptimeMillis(); //手机开机到现在的时间(毫秒为单位),手机睡眠的时间不包括再内
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do { //如果此时消息不为null,但是这个消息找不到发送它的Handler,说明为不合法消息,放弃并寻找下一条异步消息
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) { //如果消息不为null(这次是个正常消息)
if (now < msg.when) {
// 虽然消息是正常的,但是还没到发送的时间。msg.when表示消息发送的时间,因为我们可能调用了postDelay()
//延迟发送。我们之前说过,当等待nextPollTimeoutMillis时长后nativePollOnce()方法就会返回。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else { //else则表示,成功抓到了一条消息
mBlocked = false;
if (prevMsg != null) { //单链表操作,下面讲
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}
......
}
......
}
}

首先:

1
2
3
4
final long ptr = mPtr;
if (ptr == 0) {
return null;
}

这个mPtr我们之前在MessageQueue的构造方法中提到过:

1
2
3
4
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}

它通过mPtr = nativeInit();得到值,nativeInit()是一个native层的方法,根据注释来看,它主要是判断Looper目前的状态。if (ptr == 0) {表示的是当前线程的Looper已经退出或者被处理掉了,这种情况发生在“应用在退出之后试图重启Looper”的情况下,这种情况是不被允许的,因此此时return null;

  上面这段中还要讲的就是单链表的操作:

1
2
3
4
5
6
7
8
9
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse(); //表示这个消息已经被传递(使用了)
return msg;
}

首先,再synchronized (this)同步块一开始的时候,有一个全局变量mMessages,这实际上就是等待处理消息,这个变量很重要,之后我们会多次遇到。这里还有一个叫prevMsg的Message,用于保存找不到msg.target的消息(废消息)。OK,回到链表操作中来,if (prevMsg != null),很遗憾,有一个不合法的消息,此时上面已经经历了prevMsg = msg; msg = msg.next;这两步,加上prevMsg.next = msg.next;这一步,实际上就是prevMsg的后继引用跳过了msg,直接指向了msg的下一位(注意prevMsg是不合法的,但是它的下一位msg是合法的)。

  再看else,说明没有不合法的消息,Message msg = mMessages;加上mMessages = msg.next;,这两步实际上和上面一样,也是工作指针后移,越过了msg。也就是msg出队,msg的下一条消息成为mMessages(待处理消息),否则就进入一个阻塞状态,一直等到有新的消息入队。

  OK,上面if和else中越过的msg,就是我们要返回的正常消息,接着两句:msg.next = null;和return msg;就可以知道,前者是将msg的后继引用清空(将它从链表中删除),然后return。

  通过上面的分析我们知道,MessageQueue.next()作用就是遍历链表,找出一个合法的msg,将它从链表中删除后返回,这实际上也就是一个消息出队的过程

4.Handler

(1)Handler.post/sendMessage将一个消息添加到消息队列中

  上面我们已经讲完了Handler通信的两个重要的基础类——MessageQueue和Looper,接下来我们分析一下Handler是如何将一个消息发送出去的。

  我们从Handler的构造函数开始看起:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public Handler() {
this(null, false);
}
......
public Handler(Callback callback, boolean async) {
......
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

可以看到,Hnadler在发送消息的时候先获取当前线程的Looper,然后做一次looper的非空判断;接着获取了Looper中的MessageQueue对象。这样,我们的Handler已经和Looer以及MessageQueue取得了联系。

  接着回到文章最开始的时候举的那个例子中,handler.sendMessage()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

上面几个方法的逻辑都比较清晰,可以看到,最终调用了MessageQueue的enqueueMessage()方法,其中第一个参数为msg,第二个参数uptimeMillis = SystemClock.uptimeMillis() + delayMillis,也就是开机到现在的时间(不包括睡眠时间)+我们设定的delay时间,接下来我们看看enqueueMessage()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) { //目标Handler为null
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) { //msg已经用过了
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) { //如果这个Looper正在退出,回收msg,加入到消息池
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
msg.recycle(); //释放msg资源
return false;
}
msg.markInUse(); //表示这个msg已经被使用了
//这里我们可以知道,Message类的when属性实际上就是SystemClock.uptimeMillis() + delayMillis
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
//如果p == null,说明MessageQueue中没有消息;或者msg的时间是这个消息队列中最靠前的
msg.next = p; //将这个msg提取出来,并复制给mMessages,mMessages会在上面的
mMessages = msg; //MessageQueue.next()方法中进行一系列判断后返回
needWake = mBlocked; //当阻塞时需要唤醒
} else { //elss,说明此时我们发送过来的消息需要按照一定规则插入到队列中
//将消息按时间顺序插入到MessageQueue。一般地,不需要唤醒事件队列,除非
//消息队头存在barrier,并且同时Message是队列中最早的异步消息。
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next; //工作指针后移并且循环遍历链表
if (p == null || when < p.when) { //找到一个不为空并且发送时间大于当前发送时间的消息,
break; //跳出循环,准备把msg(要发送的消息)查到这条消息之前
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
② msg.next = p; // 单链表插入
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}

  MessageQueue是按照Message触发时间的先后顺序排列的,队头的消息是将要最早触发的消息。当有消息需要加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序。

  上面代码中①处的for()循环就是在循环遍历MessageQueue以找到合适的msg插位置,②处的代码实际上就是一个单链表插入的过程,我们可以把整个插入的代码连起来,这样更容易看出:

1
2
3
4
prev = p;
p = p.next;
msg.next = p;
prev.next = msg;

没骗你吧~~这就是把我们的要发送的消息msg插入到了链表中的p节点之前。

  我们需要明确的一点是,这里的Handler.post/sendMessage方法是和上面的MessageQueue.next()方法是对应的,他是消息的入队操作。

(2)Looper.loop()中调用Handler.dispatchMessage()接受并处理消息

  好了,讲到这里,我们可以看到,Handler.post或者Handler.sendMessage方法,最终是将他们要发送的消息添加到了消息队列中(Handler.post实际上也是调用了Handler.sendMessageDaley())。

  那么接受消息在哪呢?好吧看标题你也知道,Looper.loop()方法中我们实现了消息的重写与接收。我们回过头去看Looper类,在该类中MessageQueue.next()这个消息出队的方法调用完之后,出现了msg.target.dispatchMessage(msg);这句代码,我们说过这句代码中的msg.target就是消息的目标Handler,于是我们回到Handler中看下这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}

  可以看到最终我们调用了一个空方法,为什么呢,因为消息的最终回调是由我们控制的,我们在创建handler的时候会在Handler所在的线程中(如果是子线程更新主线程UI的话,就在主线程中)重写handleMessage方法,然后根据msg.what进行消息处理(对照开始给出的Hanlder常见场景)。

我们梳理一下整个流程:

1
2
3
4
5
6
7
① handler = new Handler();    //创建Handler对象
② Looper.prepare(); //准备好Looper,初始化MessageQueue
③ Message msg =Message.obtain(); //从消息池中取出一个可用的Message实例
④ msg.obj = data; //消息的数据
msg.what=1; //标志消息的标志
⑤ handler.sendMessage(msg); //发送消息,将一个消息添加到消息队列中去
⑥ Looper.loop(); //使用loop使消息队列循环起来,并进行消息的出队删除操作

Looper.loop()中的消息出队之后,将调用Handler的dispatchMessage,最终大我们在代码中重写的handleMessage用以自定处理:

1
2
3
4
5
6
7
8
9
10
11
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) { //判断标志位
case 1:
//更新UI操作
break;
}
}
};

(3)Handler.post() & View.post() & Activity.runOnUiThread()

①Handler.post()

  上面我们说了Handler.sendMessage()方法,并且在文章开头的实例中展示了Handler.sendMessage()的使用方法,下面我们来说一下Handler.post(),该方法的具体使用还是略微的有一点不同的:

1
2
3
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}

可以看到,Hander.post()方法还是调用了sendMessageDelayed方法,这跟之前的流程是一样的。这里我们要说的是sendMessageDelayed(getPostMessage(r), 0);中的getPostMessage(r)方法:

1
2
3
4
5
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}

在这个方法中将消息的callback字段的值指定为传入的Runnable对象。这个callback字段之前我们有遇到过——在Handler的dispatchMessage()方法中原来有做一个检查,如果Message的callback等于null才会去调用handleMessage()方法,否则就调用handleCallback()方法:

1
2
3
4
5
6
7
8
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
handleCallback(msg):
private static void handleCallback(Message message) {
message.callback.run();
}

这里的run也就是一开始的时候传入的run接口。也就是说,如果通过post(Runnable r)传递消息的话,我们直接就可以在post()方法中进行UI操作:

1
2
3
4
5
6
7
8
9
10
11
12
handler = new Handler();  
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
// 在这里进行UI操作
}
});
}
}).start();

写法上简洁了很多,但是本质上都是一样的。

②View.post()
(source/android-24/android/view/View):

1
2
3
4
5
6
7
8
9
10
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}

可以看到同样调用了Handler的post方法

1
2
3
4
5
6
7
8
Activity.runOnUiThread()
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}

如果当前的线程不等于UI线程(主线程),就去调用Handler的post()方法,否则就直接调用Runnable对象的run()方法。

5.Message.obtain

上面我们需要解释的一个东西便是Message msg =Message.obtain();这句,Message的obtain()方法中维护了一个消息池,其最大容量MAX_POOL_SIZE = 50

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) { //消息池不为空时从消息池中直接拿消息
Message m = sPool;
sPool = m.next; //工作指针后移,准备取出sPool
m.next = null; //从sPool中取出一个Message对象,并消息链表断开
m.flags = 0; // 清除in-use flag
sPoolSize--; //消息池的可用大小进行减1操作
return m;
}
}
return new Message(); // 当消息池为空时,直接创建Message对象
}
/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}

  我们当然可以直接new Message()这样来创建消息,但是一般来讲我们还是应该调用Message.obtain()方法来返回一个消息实例,以避免Message对象的多次创建。

好了,到此为止,我们调用Handler发送消息更新UI的整个流程就说完了。

三.Activity启动过程中UI线程的MainLooper的创建

  Actvity的启动流程我们之前在一片文章中有讲过,真正启动Activity的是ActiivtyThread类中的main()方法:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
Looper.loop();
......
}

可以看到,我们在启动一个Activity之前,我们在ActivityThread.main()方法中,调用了Looper.prepareMainLooper()方法:

1
2
3
4
5
6
7
8
9
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}

该方法同上面的Looper.prepare()方法一样,只不过这里准备的是主线程中的Looper,因此prepare(false);其中的参数false表示的是,该线程的Looper不能退出。之后调用myLooper则是获取主线程中的Looper对象,这些和上面都没什么区别。

  我们回到ActivityThread.main()中,在准备完主线程的Looper之后,ActivityThread thread = new ActivityThread();创建一个ActivityThread实例。thread.attach(false);参数false表示这不是系统进程,是给普通应用程序使用的进程。

我们接着thread.attach(false);来看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
......
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
......

注意到mgr.attachApplication(mAppThread);这句,其中mAppThread是ApplicationThread的对象,mgr为IActivityManager接口类,而真正实现IActivityManager接口的是在ActivityManagerService(AMS)类中,关于AMS类中的代码我们这里就先不详细解释了,我们只需要知道,在它当中经过一系列的处理~~最终:

1
2
3
app.thread.scheduleLaunchActivity(new Intent(r.intent), r, System.identityHashCode(r),
r.info, r.icicle, results, newIntents, !andResume, isNextTransitionForward());
}

又回调到了ActivityThread类中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//该方法在ApplicationThread(Binder线程)中调用
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}

可以看到,这里将一系列应用的信息封装在ActivityClientRecord中之后,最终调用了sendMessage(H.LAUNCH_ACTIVITY, r);发送消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}

上面的“H”实际上就是一个Handler类:private class H extends Handler {,而这里的mH则是H的子类。接着往下看:

1
2
3
4
5
6
7
8
9
10
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
......

可以看到,这里handleMessage收到了我们发送的LAUNCH_ACTIVITY也就是启动Activity的请求,实际上这里还有PAUSE_ACTIVITY,RESUME_ACTIVITY等一系列请求的处理。

之后handleLaunchActivity(r, null, “LAUNCH_ACTIVITY”);–>performLaunchActivity–>mInstrumentation.callActivityOnCreate一系列流程之后,我们的Activity就启动了,这个我们在之前的文章中有讲过,这里不再獒述。

来源:http://www.jianshu.com/p/f1da1ed7bd7e