Handler.removeCallbacks(Runnable
今天发现一个问题就是Android中使用Handle的removeCallbacks函数将Runnable移除,可是有时候会失效,在网上搜索了很久,大部分都是解决方法,依然没有说明为什么失效的原因。
在StackOverFlow找到一点原因:
It appears to me that removeCallbacks(..) only stops pending messages (Runnables). If your runnable has already started, then there's no stopping it (at least not this way).
removeCallbacks只能停止处于即将运行状态的messages,这里messages里面包含就是Runnables,如果Runnbale已经启动start(),则removeCallbacks是无法停止的。
感觉很厉害的人都是自己找问题答案的,所以今天我也要学学他们,自己找答案。
在Handler的removeCallbacks()方法是调用:
public final void removeCallbacks(Runnable r)
{
mQueue.removeMessages(this, r, null);
}
mQueue就是MessageQueue,接着看removeMessages方法
void removeMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
// 就是将当前处于mMessage前面的message(里面有目标callback)移除
while (p != null && p.target == h && p.callback == r
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();//将移除的message放入pool中
p = n;
}
// Remove all messages after front.
// 就是将当前处于后面的message(里面有目标callback)移除
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || n.obj == object)){
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
可见mQueue.removeMessages(this, r, null);是将messageQueue中的包含有我们想要移除的callback的message全部移除掉,这样不就达到阻止runnable运行的目的了吗?
但是假如我们想要移除的callback不在messageQueue中,那么mQueue.removeMessages也就失效了。
因为已经处于运行的runnable包含在message中已经移交给handler进行处理了,而Handler.removeCallbacks(Runnable r)只能移除未运行的runnable,所以导致无法停止runnbale的运行,最后失效。