Hander
Hander的主要作用有两个:
- 延迟处理消息。
- 在其他线程处理消息。
这里的消息可以理解为Message
和Runnable
,通过如下方法来调度消息。
方法 | 作用 |
---|
post(Runnable) | 将Runnable对象添加到消息队列 |
postAtTime(java.lang.Runnable, long) | 加入消息队列,在特定时间执行Runnable对象 |
postDelayed(Runnable, Object, long) | 加入消息队列,延迟执行 |
sendEmptyMessage(int) | 仅仅发送what值消息 |
sendMessage(Message) | 将Message对象加入队列 |
sendMessageAtTime(Message, long) | 同理 |
sendMessageDelayed(Message, long) | 同理 |
Runnable
实际上是将该Runnable
匿名对象排入队列,在其他线程执行该消息,这里的其他线程可以理解为MessageQueue
所在的线程。
MessageQueue和Looper
MessageQueue
是由Looper
来创建的,通过与该Looper
关联的Handler
对象往里面添加消息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| public Handler(Callback callback, boolean async) {
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 = callback;
mAsynchronous = async;
}
|
这是Handler
的构造函数,第10行代码可以看到在里面通过Looper.myLooper()
获得了Looper
对象。而2到9行代码是对Handler类是否为静态内部类的检测代码,否则会提示一个警告可能会造成内存泄漏。
另外一个值得注意的是第15行的mQueue = mLooper.mQueue
, 可以看到Looper
会把自己的MessageQueue
对象交给Handler
.
在Looper.java
中找到静态方法myLooper
,令人好奇的是sThreadLocal
里面为什么可以通过get()
方法获取到一个Looper
对象。
1
2
3
4
5
6
7
8
9
10
11
12
| public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
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.prepare()
中给sThreadLocal
中设置了Looper
对象,如果已经存在当前线程的Looper
对象则不会再次创建,而且值得注意的是不要重复调用prepare()
方法,否则会抛异常。
至此,我们已经验证了Handler
中获得了当前线程的Looper
对象,下面我们看看Looper
是怎么创建MessageQueue
的。
1
2
3
4
| private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
|
添加队列
我们来研究一下添加队列的过程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| 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");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
|
你会发现最终发送的消息是通过sendMessageAtTime
发送的,上面我们已经提到过了Looper
将MessageQueue
交给了Handler
,来看看enqueueMessage
方法。
1
2
3
4
5
6
7
| private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
|
请注意第2行的msg.target=this
,也就是这个target是Handler对象。
至此,我们已经将消息添加到了MessageQueue
了,接下来我们来看看Looper是怎么管理队列的。
管理队列
一般创建一个Handler的过程如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
|
这个Looper.loop()
静态方法内有一个无限的for循环,在这个for循环中对队列数据进行了处理和分发,下面是部分代码:
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
| 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) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
}
}
|
可以看到第17行的msg.target.dispatchMessage(msg)
,哈哈,上面已经提到了这里的msg.target
实际上是Handler对象。
1
2
3
4
5
6
7
8
9
10
11
12
| public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
|
至此,整个过程已经完成,你会发现这个过程其实很简单。
HanderThread
到现在这个HandlerThread就很好理解了,它其实是是一个线程,继承自Thread类,可以说它是对Thread的一种Looper包装,它里面实现了Looper的创建。
通常情况下我们可以拿到该线程的Looper对象来创建Handler,这样Handler的消息处理就会在HandlerThread所在线程执行。
1
2
3
| mSerialThread = new HandlerThread("serial-worker-thread");
mSerialThread.start();
mSerialThreadHandler = new Handler(mSerialThread.getLooper());
|
如果配合RxJava的线程调度就更妙了,哈哈。
1
2
3
4
5
6
7
8
|
Observable.create(new ObservableOnSubscribe<RecvCommand>() {
@Override
public void subscribe(ObservableEmitter<RecvCommand> emitter) throws Exception {
//TODO Somethings
}
}).subscribeOn(AndroidSchedulers.from(mSerialThread.getLooper()));
|
简单的说HandlerThread可以方便我们快速创建一个处理消息队列的线程,我们可以获取它的Looper对象来给相关Handler,相对应的Handler就可以给该线程发送消息。
最后我们看看HandlerThread的run()方法吧,看到这个代码是不是什么都不用说了,哈哈。
1
2
3
4
5
6
7
8
9
10
11
12
13
| @Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
|