关于Handler消息机制梳理

what

在Android开发中,Hanldler消息机制可以说无处不在,主线程的调度,View,任务提交,IntentService,Messager中都出现了,可谓无处不在。handler消息发挥作用的包含了:Handler,Looper,Message,MessagerQueue,这四个重要组成。Handler发送消息,Looper开启轮询从MessageQueue中获取消息,交由Handler处理。

how

还是从一个使用者角度先了解,具体怎么用Handler吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private Handler mHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
doSomeThing();
break;
case 2:
doSomeThing();
break;
}
super.handleMessage(msg);
}
};

private void sendMessage() {
mHandler.sendEmptyMessage(1);
}

创键Handler对象,传入Looper,发送消息。再Hanlder内部处理消息,当然还可以直接发送Runnable,或者加入延时等。用法就这么简单。下面还是具体介绍吧

Handler

可以发送消息和处理消息,可以有很多个实例,具体根据消息来分辨处理。

它的成员包括了Looper,MessageQueue,Callback

1
2
3
4
//常用api,以及加上延时等
post(Runnable);//提交任务
sendMessage(Message);//提交消息
handleMessage(Message);//处理消息

一般使用Handler有两种方法,一般是需要传入Looper,如果不则默认传入当前线程的Looper

  • 扩展Handler,重写handleMessage
  • 传入回调,回调也只需要实现handleMessage
1
2
3
4
5
6
7
//最终被调用的构造器
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;//looper
mQueue = looper.mQueue;//looper的messagequeue
mCallback = callback;//回调形式处理消息
mAsynchronous = async;//开启发送异步消息
}

Looper

这个的话管他叫轮询,反正是有循环的意思。首先它是一个ThreadLocal变量,保证了每个线程间独立运行,再而它的话就是从消息队列中取出消息,转交到Handler处理

它的成员包括了ThreadLocal,MessageQueue,Thread。

看下重要api

1
2
3
4
prepare();//获取线程本地Looper实例
loop();//进入轮询
quit();//退出
getMainLooper();//获得主线程Looper

Message

封装了消息码,触发时机,runnable,目标handler的消息,内部是一个长度50不断复用的消息池(链表结构),消息分为异步和同步

看下重要api

1
Message.obtain();//从池里获得消息

MessageQueue

尾插法实现的消息链表,异步消息优先出,称之为消息队列,但是不是那个操作系统的消息队列啊。

1
2
3
next();//拿取消息
quit();//退出
enqueueMessage();//入消息

从源码来角度再探析

本来向从主线程来分析的,但是好像不怎么完整,那就用HandlerTread来分析吧,这个就非常完整了

HandlerThread

首先这是一个Thread,内部实现了Handler消息机制,即可以通过Handler来进行提交任务和消息到线程中运行。

先看下是怎么用的:

1
2
3
4
5
HandlerThread handlerThread = new HandlerThread("test");//创键HandlerThread
handlerThrad.start();//开启线程
Handler handler = new Handler(handlerThread.getLooper());//关联Handler
handler.post(()-> System.out.println("run1"));//提交任务或者消息
handler.sendEmptyMessage(0);

用就是这么用的。原理就是handler提交消息,HandlerThread线程开启轮询,分发消息,处理。

接下来就可以分析源码了:

HandlerThread构造

首先进入HandlerThread构造方法

1
2
3
4
5
6
7
8
9
10
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
//就起了个名字而已

HandlerThread进入run

接着线程开启进入run方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
//HandlerThread.run
public void run() {
mTid = Process.myTid();//获取进程PID
Looper.prepare();//Looper准备
synchronized (this) {
mLooper = Looper.myLooper();//获取Looper
notifyAll();//唤醒
}
Process.setThreadPriority(mPriority);
onLooperPrepared();//回掉
Looper.loop();//进入Looper轮询
mTid = -1;
}

在run方法中等于说准备looper,进入轮询

准备Looper

接着看下如何准备Looper和获得Looper的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Looper.prepare
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));//创键本线程的Looper
}
//这里就是入准备本线程的Looper

//Looper.myLooper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();//获得
}

进入Looper轮询

接下就是重头戏了,进入轮询,挑关键代码看看

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
//Looper.loop
public static void loop() {
final Looper me = myLooper();//获取looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//获取MessageQueue
//...省略
for (;;) {
Message msg = queue.next(); // might block,从消息队列中获取消息,也许阻塞
if (msg == null) {
// No message indicates that the message queue is quitting.
return;//没有消息则代表队列退出了
}
//...省略
try {
msg.target.dispatchMessage(msg);//交由给Handler分发消息
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...省略
msg.recycleUnchecked();//回收消息
}
}

整个过程也还好理解,开启死循环,从消息队列中不断的拿去消息,然后由消息目标 handler进行分发处理。

接下我先看简单的handler如何分发处理消息的。待会再看如何获取消息的

消息处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Handler.dispatchMessage
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//看消息本省是否有回掉处理,额,这个callback类型其实是Runnable,其实就是看看这个消息是不是Runnable类型
handleCallback(msg);
} else {
if (mCallback != null) {//交由创键回调handleMessage的处理消息,也就实现的handleMessage
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//交由本省的handleMessage处理,也就是扩展的handleMessage
}
}

private static void handleCallback(Message message) {
message.callback.run();//直接调用runnable的run方法,完成提交任务的run
}

分发消息比较简单,首先判断这个消息是否是Runnable类型,是则直接调run,不是的在看是由本身的handleMessage处理还是回调的handleMessage处理。

取出消息

接着就看如何获取消息的:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//MessageQueue.next
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}

int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {//循环去拿出合适时机消息
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//Linux的管道基础上的,空闲等待nextPollTimeoutMillis,和传统的阻塞不一样,
//nextPollTimeoutMillis这个时间则是消息延时时间
nativePollOnce(ptr, nextPollTimeoutMillis);

synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());//优先出异步消息
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
//消息没有准备好运行,设定了延时执行,计算出延时时间,空闲等待
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//消息准备好了,出消息
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.没有消息
nextPollTimeoutMillis = -1;
}

// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}

//...省略
}
}

MessageQueue中next中进入死循环获取消息,从队列中去拿去消息,遍历队列消息,队列的消息是按照执行时刻从小到大排列的,根据当前时刻取出该执行的消息(优先取异步消息),如果时机未到则会进入空闲等待(基于linux的管道)。等到了时机则会取出消息。

这一路下来从Looper轮询,消息取出,消息执行的步骤。

接下看看是如何提交消息的

构建消息

构建消息,首先从消息复用池拿去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Message.obtain
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
//链表咯
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();//池为空则新建
}

提交消息

接着Handler提交消息,无论是runnable消息,或者空消息,或者其它的消息,或者带延时的,最终sendMessageAtTime

1
2
3
4
5
6
7
8
9
10
11
//Handler.sendMessageAtTime
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);//入消息队列
}

消息入队列

接着就是进入消息队列,执行时刻小的在前插入

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
50
51
52
53
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}

synchronized (this) {
if (mQuitting) {//如果退出
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();//回收
return false;
}

msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked. 新建链表头
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {//找到合适的位置,保证时刻顺序
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next 插入
prev.next = msg;
}

// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}

差不多流程就是这样了。这个例子使用HandlerThread做示范的,UI主线程同样也是使用这样的实现的。

IntentService

内部实现HandlerThread的Servcie,开启子线程执行,代码比较简单直接截下来了,构建HandlerThread,Handler,在onStartCommand中发送消息,并最终在onHandleIntent响应执行。

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;

private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);//调用
stopSelf(msg.arg1);//结束servcie
}
}

public IntentService(String name) {
super();
mName = name;
}

public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}

@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");//构建
thread.start();//开启

mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);//发送
}

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

@Override
public void onDestroy() {
mServiceLooper.quit();//退出
}

@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}

@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}