0%

Handler 源码解析

1 介绍

Handler在Android中起到至关重要的作用,系统本就是通过Handler的消息来驱动的,另外一个就是在Android系统中,只有主线程才能修改UI,而且存在ANR机制,所以耗时操作需要在子线程中运行,保证程序的流畅性,因此子线程中获取的数据传递给主线程更新UI,而线程通讯就是通过Handler来处理的。

2 类介绍

2.1 Handler 负责发送消息和接受消息。构造函数包含Looper,从Looper中获取消息队列,发送消息是将消息放入到消息队列中。
2.2 Looper 负责初始化消息队列和开启队列租塞读取。

3 类图和流程图

3.1 类图
类图

3.2 流程图
流程图

4 源码

4.1 Looper.prepare()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();  

/**
* 给当前线程设置一个局部变量Looper。每个线程只能设置一个Looper
*/
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}

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

主要是创建一个Looper,然后设置到线程局部变量中(ThreadLocal详细可自己了解),所以每个线程对应一个Looper,而Looper里面包含一个消息队列,再次初始化会异常。

4.2 Handler()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
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 = null;
}

public Handler(Looper looper) {
...
}

主要包含两个构造参数,如果不传Looper就会使用Looper.myLooper()通过线程局部变量获取当前线程的Looper对象,如果传递Looper,就直接使用传递进来的Looper对象。Handler最终执行方法所在的线程取决于使用哪个线程的Looper。

4.3 Looper.loop()

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
public static void loop() {  
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me.mQueue;

while (true) {
Message msg = queue.next(); // might block 这里阻塞等待消息。
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}

long wallStart = 0;
long threadStart = 0;

// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}

msg.target.dispatchMessage(msg);

msg.recycle();//这里回收消息, 实例化Message使用Message.obtain()获取回收对象。
}
}
}

开启循环阻塞获取消息并分发,执行msg.target.dispatchMessage(msg),这里的msg.targer就是Handler。

4.4 Handler.sendMessage

1
2
3
4
5
6
7
8
9
public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
{
MessageQueue queue = mQueue; //这里的消息队列就是当前线程的消息队列,是从Looper中获取的。
if (queue != null) {
msg.target = this; //msg.target 就是handler自己
sent = queue.enqueueMessage(msg, uptimeMillis);
}
return sent;
}

就是将消息放入到消息队列中。

4.5 MessageQueue.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
final boolean enqueueMessage(Message msg, long when) {  
final boolean needWake;
synchronized (this) {
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}

这里存储的方式是链表形式,主要是针对消息的执行时间排序。

5 思考

为什么平时开发在主线程中没有调用Looper.prepare和Looper.loop也能直接使用Handler?
可以看看ActivityThread中进程初始化的操作中已经在主线程中操作过这些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static final void main(String[] args) {  

Looper.prepareMainLooper(); //这里执行的prepare
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}

ActivityThread thread = new ActivityThread();
thread.attach(false);

if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}

Looper.loop(); //这里loop
}
}