如何从通过postDelayed添加的handler对象中移除一个可运行对象?

79

我有一个“打开”动画,并使用Handler.postDelayed(Runnable, delay)在短暂延迟后触发“关闭”动画。然而,在打开和关闭之间的时间内,可能会因为点击触发另一个动画。

我的问题是,我该如何在处理程序中取消“关闭”动画?


如果您使用Kotlin,请注意此答案:https://dev59.com/TXA65IYBdhLWcg3wyh97#30905295,我尝试过并遇到了这个问题(仅在Kotlin中):https://stackoverflow.com/questions/62405834/android-handler-callback-not-removed-for-token-type-int-or-long-kotlin - Ultimo_m
4个回答

109

10
能否删除匿名 runnable 的回调函数? - Bruce Lee
10
我不这么认为...你需要使用非匿名的账号。否则,你将来无法引用它们。 - Cristian
3
请参考@NameSpace的答案。如果您使用带有标记的可运行对象发布它,则可以删除待处理的可运行对象。或者,您可以使用Daniel L.的方法,使用空标记来删除所有回调/消息。 - vman
有没有推荐的方法可以移除那些没有提供removeCallbacks(Runnable r)函数的API中特定的回调函数? - gom1
这会删除所有实例的出现吗?因为我会以不同的延迟时间多次发布它。 - yeshu

103

Cristian的回答是正确的,但与回答评论所述的相反,您实际上可以通过调用removeCallbacksAndMessages(null);来删除匿名Runnables的回调。

正如这里所述:

删除任何待处理的回调和已发送的消息,其obj为令牌。如果令牌为null,则将删除所有回调和消息


7
我想指出的是,当你处理HandlerView类时,这种行为是不同的。在一个View类中(也许从4.0开始?),你必须使用相同的Runnable对象来取消任务,而对于一个Handler类,如果你传递null,它们将被全部取消。尽管如此,问题中指定了一个Handler,所以你的答案是正确的。 - Andre
1
真的!!谢谢..我有一些可运行的代码,但是removeCallbacks什么也没做!!!但这确实起作用了:) 谢谢 - cV2

17

虽然回答晚了,但是这里有一种不同的方法可以仅从处理程序中删除特定类别的可运行对象(即在 OP 的情况下,只删除关闭动画,而保留队列中的其他可运行对象):

    int firstToken = 5;
    int secondToken = 6;

    //r1 to r4 are all different instances or implementations of Runnable.  
    mHandler.postAtTime(r1, firstToken, 0);
    mHandler.postAtTime(r2, firstToken, 0);
    mHandler.postAtTime(r3, secondToken, 0);

    mHandler.removeCallbacksAndMessages(firstToken);

    mHandler.postAtTime(r4, firstToken, 0);

上述代码仅会执行 "r3" 和 "r4"。这样,您就可以删除由您的令牌定义的特定类别的可运行对象,而无需保留对可运行对象本身的任何引用。

注意: 源代码只使用“==”运算符比较令牌(不调用 .equals()),因此最好使用整数/ Integer 而不是字符串作为令牌。


我看到了你的回答,于是我从 string 改成了 int,然后我就有了这个 bug 一整天 :D https://stackoverflow.com/q/62405834/2736039 - Ultimo_m
这在 Kotlin 中对于 int > 127 不起作用,只是留下这个评论作为未来读者的提示。 - Ultimo_m
这个方法不可靠,即使在Java中也不行!https://stackoverflow.com/a/63571523/361413有一个非常好的解释。 - undefined

11
如果您使用递归,可以通过传递"this"来实现这一点。请参见下面的代码。
public void countDown(final int c){
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            aq.id(R.id.timer).text((c-1)+"");
            if(c <= 1){
                aq.id(R.id.timer).gone();
                mHandler.removeCallbacks(this);
            }else{
                countDown(c-1);
            }
        }
    }, 1000);
}

这个例子将每秒设置一个TextView(计时器)的文本,倒计时。一旦它到达0,它将从UI中删除TextView并禁用倒计时。对于使用递归的人来说,这很有用,但我是通过搜索找到这里的,所以我发布了我的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接