AndroidでHandlerのpost(Runnable r)
を複数回コールした場合は、postした順にQueueに積まれて、実行されます。post(Runnable r)
とpostDelayed(Runnable r, long delayMillis)
を使った場合にどうQueueに積まれるか調べてみました。
ソースコードを見ると、postとpostDelayedの内部では共にsendMessageDelayed(Message msg, long delayMillis)
が呼ばれていました。
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
sendMessageDelayedの中ではsendMessageAtTime(Message msg, long uptimeMillis)
が呼ばれており、引数のuptimeMillisにはSystemClock.uptimeMillis() + delayMillis
が設定されています。
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
つまり、postDelayed(Runnable r, long delayMillis)
はdelayMillis ミリ秒後にpost(Runnable r)
をするのと同じことになります。
例えば、下記のコードを実行すると、
val handler = Handler()
handler.postDelayed( Runnable { Log.d(TAG, "Runnable 1") }, 100)
Log.d(TAG, "1 postDelayed")
handler.post( Runnable {
Log.d(TAG, "Runnable 2-1")
Thread.sleep(100)
Log.d(TAG, "Runnable 2-2")
})
Log.d(TAG, "2 post")
handler.post( Runnable {
Log.d(TAG, "Runnable 3-1")
Thread.sleep(200)
Log.d(TAG, "Runnable 3-2")
})
Log.d(TAG, "3 post")
ログは下記のようになります。
2020-02-08 20:08:07.385 22994-22994/Sample: 1 postDelayed
2020-02-08 20:08:07.385 22994-22994/Sample: 2 post
2020-02-08 20:08:07.385 22994-22994/Sample: 3 post
2020-02-08 20:08:07.490 22994-22994/Sample: Runnable 2-1
2020-02-08 20:08:07.591 22994-22994/Sample: Runnable 2-2
2020-02-08 20:08:07.592 22994-22994/Sample: Runnable 3-1
2020-02-08 20:08:07.793 22994-22994/Sample: Runnable 3-2
2020-02-08 20:08:07.950 22994-22994/Sample: Runnable 1
Runnable 1
はRunnable 3
の後に実行されます。
また、postDelayed
はdelayMillisを100msにしていますが、実際に実行されるのは565ms後です。
Runnable 1
が、Runnable 3
の前または、100ms後に実行されることを想定していると、思わぬ不具合を生むことになるので注意が必要です。