说说 Handler

依据维基百科对 Handler 在计算机领域中的解释,Handler 就是一个异步回调子程序.

而对于异步回调,我们想象一个在做饭的场景.锅里还吵着菜,这时候你需要烧一壶水,当你按下烧水开关的时候,你不会去等待水烧开,而是在继续翻炒,等水烧开了发出嘟嘟的声音,你才会再去理会这壶开水.而这个场景中,Handler可以理解为嘟嘟声,由于这个嘟嘟声我们注意力从锅转向了烧水壶.

话锋一转,让我们看看 Android 中的 Handler 是不是也是这么回事情呢.

Handler 允许你能够发送和处理 Message 和 Runnable 对象,而这些对象都是与具体线程的 MessageQueue相关联的.每个 Handler 实例都是与具体线程以及此线程的 MessageQueue 相关联的.当你创建了一个新的Handler的时候,它就与具体线程以及此线程所创建的 MessageQueue 绑定在一起了.它会发 Message 和 Runnable 对象给 MessageQueue 并在这些对象从 MessageQueue 中出来的时候 执行他们.

Handler 有两个主要用途:

  • 调度 Message 和 Runnable 对象,使其在将来的某个时间点被执行.
  • 将一个行为过程压入队列,使其能够在非当前线程上执行

消息的调度是由 post 系列方法

  • post
  • postAtTime(Runnable,long)
  • postDelay

以及 send 系列方法

  • sendEmptyMessage
  • sendMessage
  • sendMessageAtTime
  • sendMessageDelayed

等方法完成的.

post 系列让你能够压入 Runnabled 对象到队列中,而当消息被接受到的时候,Runnable 会被执行. sendMessage系列让你能够压入包含数据包的 Message 对象,而这个消息对象会在 Handler的 handleMessage 方法中被处理,当然你需要实现一个 Handler 的子类.

当你的应用进程创建的时候,它的主线程就专用于运行一个消息队列,而这个线程负责管理顶层的应用对象,Activity,broadcast reveivers 等以及所有它们创建的窗口.你可以创建自己的线程,然后通过 Handler 与应用的主线程进行通讯.还是同样调用 post 和 sendMessage 方法,但是是从你的线程这边调用.给定的 Runnable 和 Message 会在 Handler 的 message queue 中被调度并在合适的时候被处理.

细节分析:

1
2
3
4
5
6
7
8
9
10
11
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*/
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}

当你想避免实现你的Handler子类的时候,你可以使用这个回调接口.并且如果Message对象没有进一步处理的时候 handleMessage 方法 会返回 true.

1
2
3
4
5
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}

子类必须实现这个方法才能接收到消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

系统消息是在这里被处理的.

1
2
3
4
5
6
7
8
9
10
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}

Handler 的 默认构造器, 将此 Handler与 当前线程的 Looper 相关联.如果该线程没有Lopper的话,这个handler就没有接收消息的能力,然后就抛出异常了.

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Constructor associates this handler with the {@link Looper} for the
* current thread and takes a callback interface in which you can handle
* messages.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(@Nullable Callback callback) {
this(callback, false);
}

同样这个构造器也是将 Handler与当前线程的Looper相关联的,只不过多了一个 callback 接口参数,实现这个接口你就能处理消息了.

1
2
3
4
5
6
7
8
9

/**
* Use the provided {@link Looper} instead of the default one.
*
* @param looper The looper, must not be null.
*/
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}

使用提供的Looper,而不是默认的Looper

1
2
3
4
5
6
7
8
9
10
11

/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}

使用提供的Looper,而不是默认的Looper,并且多个一个callback 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

/**
* Use the {@link Looper} for the current thread
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
@UnsupportedAppUsage
public Handler(boolean async) {
this(null, async);
}

使用当前线程的Looper,然后对 handler 是异步还是同步进行设置.

Handler默认是异步的,除非构造器里明确指定为同步的.

同步消息意味着中断和事件,不需要像异步消息那样需要全局的顺序.同样同步消息不受限于由 MessageQueue#enqueueSyncBarrier(long)引入的 synchronzation barrier.

如果 async 参数被设置为 true,handler就会在每个发送到它的消息和Runnable上调用 Message#setAsynchronous(boolean)方法

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

/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(@Nullable 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 " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

多了一个callback参数

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

/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by conditions such as display vsync.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

可以指定 Looper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

/**
* Create a new Handler whose posted messages and runnables are not subject to
* synchronization barriers such as display vsync.
*
* <p>Messages sent to an async handler are guaranteed to be ordered with respect to one another,
* but not necessarily with respect to messages from other Handlers.</p>
*
* @see #createAsync(Looper, Callback) to create an async Handler with custom message handling.
*
* @param looper the Looper that the new Handler should be bound to
* @return a new async Handler instance
*/
@NonNull
public static Handler createAsync(@NonNull Looper looper) {
if (looper == null) throw new NullPointerException("looper must not be null");
return new Handler(looper, null, true);
}

创建一个同步的,可以指定Looper的 Handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

/**
* Create a new Handler whose posted messages and runnables are not subject to
* synchronization barriers such as display vsync.
*
* <p>Messages sent to an async handler are guaranteed to be ordered with respect to one another,
* but not necessarily with respect to messages from other Handlers.</p>
*
* @see #createAsync(Looper) to create an async Handler without custom message handling.
*
* @param looper the Looper that the new Handler should be bound to
* @return a new async Handler instance
*/
@NonNull
public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
if (looper == null) throw new NullPointerException("looper must not be null");
if (callback == null) throw new NullPointerException("callback must not be null");
return new Handler(looper, callback, true);
}

同步的,可以指定Handler,并且带有 callback 参数

1
2
3
4
5
6
7
8
9
10

/** @hide */
@UnsupportedAppUsage
@NonNull
public static Handler getMain() {
if (MAIN_THREAD_HANDLER == null) {
MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
}
return MAIN_THREAD_HANDLER;
}

获取 Main Handler

1
2
3
4
5
/** @hide */
@NonNull
public static Handler mainIfNull(@Nullable Handler handler) {
return handler == null ? getMain() : handler;
}

如果 handler为空则获取 main Handler

1
2
3
4
5
6
7
8
9
10
/**
* Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
* creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
* If you don't want that facility, just call Message.obtain() instead.
*/
@NonNull
public final Message obtainMessage()
{
return Message.obtain(this);
}

从全局消息池中获取消息,比新建实例更为高效

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
/**
* Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.
*
* @param what Value to assign to the returned Message.what field.
* @return A Message from the global message pool.
*/
@NonNull
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}

/**
*
* Same as {@link #obtainMessage()}, except that it also sets the what and obj members
* of the returned Message.
*
* @param what Value to assign to the returned Message.what field.
* @param obj Value to assign to the returned Message.obj field.
* @return A Message from the global message pool.
*/
@NonNull
public final Message obtainMessage(int what, @Nullable Object obj) {
return Message.obtain(this, what, obj);
}

/**
*
* Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned
* Message.
* @param what Value to assign to the returned Message.what field.
* @param arg1 Value to assign to the returned Message.arg1 field.
* @param arg2 Value to assign to the returned Message.arg2 field.
* @return A Message from the global message pool.
*/
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2)
{
return Message.obtain(this, what, arg1, arg2);
}

/**
*
* Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the
* returned Message.
* @param what Value to assign to the returned Message.what field.
* @param arg1 Value to assign to the returned Message.arg1 field.
* @param arg2 Value to assign to the returned Message.arg2 field.
* @param obj Value to assign to the returned Message.obj field.
* @return A Message from the global message pool.
*/
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
return Message.obtain(this, what, arg1, arg2, obj);
}

从消息池中获取Message对象并进行赋值.

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
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}

/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}

让 Runnable r 添加到消息队列中去, runnable 会运行在 handler 相关联的 线程上

如果Runnable被成功放进消息队列的话,就会返回true.失败的话就返回false,通常是是因为处理消息队列的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
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
/**
* Runs the specified task synchronously.
* <p>
* If the current thread is the same as the handler thread, then the runnable
* runs immediately without being enqueued. Otherwise, posts the runnable
* to the handler and waits for it to complete before returning.
* </p><p>
* This method is dangerous! Improper use can result in deadlocks.
* Never call this method while any locks are held or use it in a
* possibly re-entrant manner.
* </p><p>
* This method is occasionally useful in situations where a background thread
* must synchronously await completion of a task that must run on the
* handler's thread. However, this problem is often a symptom of bad design.
* Consider improving the design (if possible) before resorting to this method.
* </p><p>
* One example of where you might want to use this method is when you just
* set up a Handler thread and need to perform some initialization steps on
* it before continuing execution.
* </p><p>
* If timeout occurs then this method returns <code>false</code> but the runnable
* will remain posted on the handler and may already be in progress or
* complete at a later time.
* </p><p>
* When using this method, be sure to use {@link Looper#quitSafely} when
* quitting the looper. Otherwise {@link #runWithScissors} may hang indefinitely.
* (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
* </p>
*
* @param r The Runnable that will be executed synchronously.
* @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
*
* @return Returns true if the Runnable was successfully executed.
* Returns false on failure, usually because the
* looper processing the message queue is exiting.
*
* @hide This method is prone to abuse and should probably not be in the API.
* If we ever do make it part of the API, we might want to rename it to something
* less funny like runUnsafe().
*/
public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}

if (Looper.myLooper() == mLooper) {
r.run();
return true;
}

BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Remove any pending posts of Runnable r that are in the message queue.
*/
public final void removeCallbacks(@NonNull Runnable r) {
mQueue.removeMessages(this, r, null);
}

/**
* Remove any pending posts of Runnable <var>r</var> with Object
* <var>token</var> that are in the message queue. If <var>token</var> is null,
* all callbacks will be removed.
*/
public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
mQueue.removeMessages(this, r, token);
}

退出的时候,移除队列中的消息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@UnsupportedAppUsage
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}

private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}

看到了Binder的痕迹

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
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;

public BlockingRunnable(Runnable task) {
mTask = task;
}

@Override
public void run() {
try {
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}

public boolean postAndWait(Handler handler, long timeout) {
if (!handler.post(this)) {
return false;
}

synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}

阻塞式的 Runnable 静态内部类.