取消一个 handler.postDelayed 进程

269
我正在使用 handler.postDelayed() 函数来创建应用程序下一阶段之前的等待时间。在等待期间,我会显示一个带有进度条和“取消”按钮的对话框。
我的问题是,在时间到期之前,我找不到一种方法来取消 postDelayed 任务。

希望这个代码片段有所帮助 https://gist.github.com/imammubin/a587192982ff8db221da14d094df6fb4MainActivity作为屏幕启动器,使用handler和runable函数,runnable函数用于基于Firebase的基本偏好设置登录用户并跳转到登录页面或反馈页面。 - Imam Mubin
5个回答

497

我这样做是为了发布一个延迟的可运行对象:

myHandler.postDelayed(myRunnable, SPLASH_DISPLAY_LENGTH); 

要移除它,可以使用以下代码:myHandler.removeCallbacks(myRunnable);


77
如果你能够承担取消 handler 上的所有回调和消息,且不想保留对可运行对象的引用,那么这个问题的已接受答案中的第三点提供了另一种看似适用于我的情况的替代方法: https://dev59.com/Pmgu5IYBdhLWcg3we2-t (基本上是调用 myHandler.removeCallbacksAndMessages(null);)。 - Mick
removeCallbacksAndMessages可以解决问题,但我个人更喜欢对预定的Runnable进行控制。实例化和处理一对Runnable不会影响您的应用程序性能;否则,如果您需要超过两个或三个Runnable,则可能需要更强大的工具,我的看法是这样的。 - andrea.rinaldi

72

如果您有多个内部/匿名运行任务传递给同一个处理程序,并且希望在同一事件中取消所有任务,请使用

handler.removeCallbacksAndMessages(null);

根据文档,

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


这将一次性删除所有可运行的回调。否则,调用 removeCallbacks(callback) 来删除特定的回调。 - FindOutIslamNow

17

另一种方法是直接处理Runnable本身:

Runnable r = new Runnable {
    public void run() {
        if (booleanCancelMember != false) {
            //do what you need
        }
    }
}

14
booleanCancelMember必须是final吗?这意味着它不能被更改,因此对于此目的无用,对吗? - stealthcopter
9
不是必须的。 - Benoit Jadinon
7
即使 Runnable 是匿名的,它也不必是最终的。它可以成为封闭类中的成员。 - Martin
6
不给这个留下反对票,但要小心。使用这种方法,如果多个Runnable被延迟发布,可能会遇到令人讨厌的竞态条件。这不会取消Runnable,因此代码是否执行取决于booleanCancelMember在每个发布的Runnable的特定时刻的值。这可能很快变得难以预测。 - Dennis K
1
如果Runnable不是匿名的,这意味着我有一个对它的引用(在这种情况下为r),这意味着我可以使用myHandler.removeCallbacks(r);。如果Runnable是匿名的,则标志将成为封闭类中的成员,这意味着我需要引用该对象来更改标志,这又意味着我仍然需要r,这意味着我仍然可以使用myHandler.removeCallbacks(r);。如果我正在执行myHandler.removeCallbacks(r);,则根本不需要这样的标志。我有什么遗漏吗? - nacho4d
显示剩余5条评论

1
这是一个为延迟操作提供取消方法的类。
public class DelayedAction {

private Handler _handler;
private Runnable _runnable;

/**
 * Constructor
 * @param runnable The runnable
 * @param delay The delay (in milli sec) to wait before running the runnable
 */
public DelayedAction(Runnable runnable, long delay) {
    _handler = new Handler(Looper.getMainLooper());
    _runnable = runnable;
    _handler.postDelayed(_runnable, delay);
}

/**
 * Cancel a runnable
 */
public void cancel() {
    if ( _handler == null || _runnable == null ) {
        return;
    }
    _handler.removeCallbacks(_runnable);
}}

0

当我通过布尔值将CancelCallBacks(this)在postDelayed可运行程序中调用时,它对我起作用了

Runnable runnable = new Runnable(){
    @Override
    public void run() {
        Log.e("HANDLER", "run: Outside Runnable");
        if (IsRecording) {
            Log.e("HANDLER", "run: Runnable");
            handler.postDelayed(this, 2000);
        }else{
            handler.removeCallbacks(this);
        }
    }
};

3
你的代码中没有“CancelCallBacks”。也许是因为它不存在? :) - The incredible Jan

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