如何从处理程序中删除所有回调?

发布于 2024-11-05 04:40:09 字数 534 浏览 0 评论 0原文

我的子活动中有一个由主活动调用的 Handler 活动。此处理程序由子类使用 postDelay 一些 Runnables,我无法管理它们。现在,在 onStop 事件中,我需要在完成 Activity 之前删除它们(不知何故我调用了 finish(),但它仍然一次又一次地调用)。是否有办法从处理程序中删除所有回调?

I have a Handler from my sub-Activity that was called by the main Activity. This Handler is used by sub-classes to postDelay some Runnables, and I can't manage them. Now, in the onStop event, I need to remove them before finishing the Activity (somehow I called finish(), but it still call again and again). Is there anyway to remove all callbacks from a Handler?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

暖树树初阳… 2024-11-12 04:40:09

根据我的经验,这非常有效!

handler.removeCallbacksAndMessages(null);

在removeCallbacksAndMessages的文档中它说......

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

In my experience calling this worked great!

handler.removeCallbacksAndMessages(null);

In the docs for removeCallbacksAndMessages it says...

Remove any pending posts of callbacks and sent messages whose obj is token. If token is null, all callbacks and messages will be removed.

撩人痒 2024-11-12 04:40:09

对于任何特定的 Runnable 实例,调用 Handler.removeCallbacks()。请注意,它使用 Runnable 实例本身来确定要取消注册的回调,因此,如果您每次发布帖子时都创建一个新实例,则需要确保引用了确切的 Runnable 取消。示例:

Handler myHandler = new Handler();
Runnable myRunnable = new Runnable() {
    public void run() {
        //Some interesting task
    }
};

您可以调用 myHandler.postDelayed(myRunnable, x) 来将另一个回调发送到代码中其他位置的消息队列,并使用 myHandler.removeCallbacks(myRunnable) 删除所有挂起的回调 不幸的是

,即使您向 MessageQueue 对象发出请求,您也不能简单地“清除”Handler 的整个 MessageQueue与它关联是因为添加和删除项目的方法受包保护(只有 android.os 包中的类可以调用它们)。您可能需要创建一个精简的 Handler 子类来管理发布/执行的 Runnable 列表...或者查看另一种范例,用于在每个 Runnable 之间传递消息活动

希望有帮助!

For any specific Runnable instance, call Handler.removeCallbacks(). Note that it uses the Runnable instance itself to determine which callbacks to unregister, so if you are creating a new instance each time a post is made, you need to make sure you have references to the exact Runnable to cancel. Example:

Handler myHandler = new Handler();
Runnable myRunnable = new Runnable() {
    public void run() {
        //Some interesting task
    }
};

You can call myHandler.postDelayed(myRunnable, x) to post another callback to the message queue at other places in your code, and remove all pending callbacks with myHandler.removeCallbacks(myRunnable)

Unfortunately, you cannot simply "clear" the entire MessageQueue for a Handler, even if you make a request for the MessageQueue object associated with it because the methods for adding and removing items are package protected (only classes within the android.os package can call them). You may have to create a thin Handler subclass to manage a list of Runnables as they are posted/executed...or look at another paradigm for passing your messages between each Activity

Hope that Helps!

山色无中 2024-11-12 04:40:09

定义一个新的处理程序并可运行:

private Handler handler = new Handler(Looper.getMainLooper());
private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // Do what ever you want
        }
    };

延迟调用后:

handler.postDelayed(runnable, sleep_time);

从处理程序中删除回调:

handler.removeCallbacks(runnable);

Define a new handler and runnable:

private Handler handler = new Handler(Looper.getMainLooper());
private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // Do what ever you want
        }
    };

Call post delayed:

handler.postDelayed(runnable, sleep_time);

Remove your callback from your handler:

handler.removeCallbacks(runnable);
一指流沙 2024-11-12 04:40:09

请注意,应该在类作用域中定义一个 Handler 和一个 Runnable,以便它被创建一次。removeCallbacks(Runnable) 可以正常工作,除非人们多次定义它们。请查看以下示例以更好地理解:

不正确的方式:

    public class FooActivity extends Activity {
           private void handleSomething(){
                Handler handler = new Handler();
                Runnable runnable = new Runnable() {
                   @Override
                   public void run() {
                      doIt();
                  }
               };
              if(shouldIDoIt){
                  //doIt() works after 3 seconds.
                  handler.postDelayed(runnable, 3000);
              } else {
                  handler.removeCallbacks(runnable);
              }
           }

          public void onClick(View v){
              handleSomething();
          }
    } 

如果您调用 onClick(..) 方法,则在调用之前永远不会停止 doIt() 方法的调用。因为每次都会创建新的 Handler 和新的 Runnable 实例。这样,您就丢失了属于 handlerrunnable 实例的必要引用。

正确的方法:

 public class FooActivity extends Activity {
        Handler handler = new Handler();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                doIt();
            }
        };
        private void handleSomething(){
            if(shouldIDoIt){
                //doIt() works after 3 seconds.
                handler.postDelayed(runnable, 3000);
            } else {
                handler.removeCallbacks(runnable);
            }
       }

       public void onClick(View v){
           handleSomething();
       }
 } 

通过这种方式,您不会丢失实际引用,并且 removeCallbacks(runnable) 可以成功工作。

关键句子是“在您使用的ActivityFragment中将它们定义为全局”

Please note that one should define a Handler and a Runnable in class scope, so that it is created once.removeCallbacks(Runnable) works correctly unless one defines them multiple times. Please look at following examples for better understanding:

Incorrect way :

    public class FooActivity extends Activity {
           private void handleSomething(){
                Handler handler = new Handler();
                Runnable runnable = new Runnable() {
                   @Override
                   public void run() {
                      doIt();
                  }
               };
              if(shouldIDoIt){
                  //doIt() works after 3 seconds.
                  handler.postDelayed(runnable, 3000);
              } else {
                  handler.removeCallbacks(runnable);
              }
           }

          public void onClick(View v){
              handleSomething();
          }
    } 

If you call onClick(..) method, you never stop doIt() method calling before it call. Because each time creates new Handler and new Runnable instances. In this way, you lost necessary references which belong to handler and runnable instances.

Correct way :

 public class FooActivity extends Activity {
        Handler handler = new Handler();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                doIt();
            }
        };
        private void handleSomething(){
            if(shouldIDoIt){
                //doIt() works after 3 seconds.
                handler.postDelayed(runnable, 3000);
            } else {
                handler.removeCallbacks(runnable);
            }
       }

       public void onClick(View v){
           handleSomething();
       }
 } 

In this way, you don't lost actual references and removeCallbacks(runnable) works successfully.

Key sentence is that 'define them as global in your Activity or Fragment what you use'.

成熟的代价 2024-11-12 04:40:09

如果您没有 Runnable 引用,则在第一个回调中获取消息的 obj,然后使用 removeCallbacksAndMessages() 删除所有相关回调。

If you don't have the Runnable references, on the first callback, get the obj of the message, and use removeCallbacksAndMessages() to remove all related callbacks.

梦里兽 2024-11-12 04:40:09

正如josh527所说,handler.removeCallbacksAndMessages(null);可以工作。
但为什么呢?
如果你看一下源代码,你会更清楚地理解。
有 3 种类型的方法可以从处理程序(MessageQueue)中删除回调/消息:

  1. 通过回调(和令牌)删除
  2. 通过消息删除(和令牌)
  3. 通过令牌删除

Handler.java(保留一些重载方法)

/**
 * 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(Runnable r, Object token)
{
    mQueue.removeMessages(this, r, token);
}

/**
 * Remove any pending posts of messages with code 'what' and whose obj is
 * 'object' that are in the message queue.  If <var>object</var> is null,
 * all messages will be removed.
 */
public final void removeMessages(int what, Object object) {
    mQueue.removeMessages(this, what, object);
}

/**
 * Remove any pending posts of callbacks and sent messages whose
 * <var>obj</var> is <var>token</var>.  If <var>token</var> is null,
 * all callbacks and messages will be removed.
 */
public final void removeCallbacksAndMessages(Object token) {
    mQueue.removeCallbacksAndMessages(this, token);
}

MessageQueue.java do真正的工作:

void removeMessages(Handler h, int what, Object object) {
    if (h == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}

void removeMessages(Handler h, Runnable r, Object object) {
    if (h == null || r == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h && p.callback == r
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        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;
        }
    }
}

void removeCallbacksAndMessages(Handler h, Object object) {
    if (h == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h
                && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}

As josh527 said, handler.removeCallbacksAndMessages(null); can work.
But why?
If you have a look at the source code, you can understand it more clearly.
There are 3 type of method to remove callbacks/messages from handler(the MessageQueue):

  1. remove by callback (and token)
  2. remove by message.what (and token)
  3. remove by token

Handler.java (leave some overload method)

/**
 * 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(Runnable r, Object token)
{
    mQueue.removeMessages(this, r, token);
}

/**
 * Remove any pending posts of messages with code 'what' and whose obj is
 * 'object' that are in the message queue.  If <var>object</var> is null,
 * all messages will be removed.
 */
public final void removeMessages(int what, Object object) {
    mQueue.removeMessages(this, what, object);
}

/**
 * Remove any pending posts of callbacks and sent messages whose
 * <var>obj</var> is <var>token</var>.  If <var>token</var> is null,
 * all callbacks and messages will be removed.
 */
public final void removeCallbacksAndMessages(Object token) {
    mQueue.removeCallbacksAndMessages(this, token);
}

MessageQueue.java do the real work:

void removeMessages(Handler h, int what, Object object) {
    if (h == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}

void removeMessages(Handler h, Runnable r, Object object) {
    if (h == null || r == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h && p.callback == r
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        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;
        }
    }
}

void removeCallbacksAndMessages(Handler h, Object object) {
    if (h == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h
                && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}
夢归不見 2024-11-12 04:40:09

这些解决方案都不适合我。但我找到了一个有效的解决方案。

即使在调用handler.removeCallbacksAndMessages(null)之后,已添加到处理程序队列中的可运行对象也会被执行。当我尝试停止线程时,导致错误:

W/MessageQueue(6436): java.lang.RuntimeException: Handler (android.os.Handler) {416659f0} sending message to a Handler on死线程

我的解决方案:

  • 删除所有回调。你需要所有的参考
    可以存储在 ArrayList 中的可运行对象。

     private ArrayList; runnableQueue=new ArrayList();
    
  • 然后每次你想发布一个可运行的文件时,将其存储在数组中,然后使用 handler.post() 发布数组项。

    private void postInHandler(){
      @覆盖
      runnableQueue.add(new Runnable() {
          公共无效运行(){   
              //你的代码 
          }
      });
      //发布数组中的最后一项 
      handler.post(runnableQueue.get(runnableQueue.size()-1));
      }
    
  • 然后要删除所有回调,请使用此方法,该方法将通过迭代数组来删除每个回调。

     private void removeHandlerCallbacks(){
         for(可运行可运行:可运行队列){
             networkHandler.removeCallbacks(runnable,null);
         }
         runnableQueue.clear();
     }
    
  • 万岁!队列被清除。 但是等等。清除数组后,我们必须确保在停止线程之前,处理程序中不再发布可运行的内容。所以你必须声明:

    布尔值allowPosting=true;

因此包括以下内容:

private void removeHandlerCallbacks(){           
    allowPosting=false;//add this line to stop posting after clearing the array
    for(Runnable runnable:runnableQueue){
        handler.removeCallbacks(runnable,null);
    }
     //Dont forget to clear the array
     runnableQueue.clear();
}

然后在处理程序中发布之前检查条件:

if(allowPosting){
    postInHandler();
}

就这样,现在队列已清除,我们确信不再发布可运行的内容清除队列后。所以停止线程是安全的。

None of the solutions worked for me. But I found a solution that worked.

The runnables already added in the handler queue got executed even after calling handler.removeCallbacksAndMessages(null). When I tried to stop the thread, it resulted in the error:

W/MessageQueue(6436): java.lang.RuntimeException: Handler (android.os.Handler) {416659f0} sending message to a Handler on a dead thread

My solution:

  • To remove all the callbacks. you need the reference for all the
    runnables which can be stored in an ArrayList.

     private ArrayList<Runnable> runnableQueue=new ArrayList<Runnable>();
    
  • Then every time u want to post a runnable, store it in the array, then post the array item using handler.post().

    private void postInHandler(){
      @override
      runnableQueue.add(new Runnable() {
          public void run() {   
              //your code 
          }
      });
      //Post the last item in the array 
      handler.post(runnableQueue.get(runnableQueue.size()-1));
      }
    
  • Then to remove all the callbacks use this method which will remove each callback by iterating through the array.

      private void removeHandlerCallbacks(){
         for(Runnable runnable:runnableQueue){
             networkHandler.removeCallbacks(runnable,null);
         }
         runnableQueue.clear();
     }
    
  • Hurray! the queue is cleared. But wait. After clearing the array we have to make sure that no more runnable is posted in the handler before you stop the thread. So you have to declare:

    boolean allowPosting=true;

so include this:

private void removeHandlerCallbacks(){           
    allowPosting=false;//add this line to stop posting after clearing the array
    for(Runnable runnable:runnableQueue){
        handler.removeCallbacks(runnable,null);
    }
     //Dont forget to clear the array
     runnableQueue.clear();
}

Then check the condition before posting in the handler:

if(allowPosting){
    postInHandler();
}

That's all, now the queue is cleared and we are sure that no more runnable is posted after clearing the queue. So it is safe to stop the thread.

梦罢 2024-11-12 04:40:09

文档removeCallbacksAndMessages(null) 删除所有回调,但并不总是如此。试试这个:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    handler.removeCallbacksAndMessages("ACTION_NAME")
    handler.postDelayed(runnable, "ACTION_NAME", 10_000) //if you want restart runnable
} else {
    handler.removeCallbacksAndMessages(null)
    handler.postDelayed(runnable, 10_000) //if you want restart runnable
}

The documentation says that removeCallbacksAndMessages(null) removes all callbacks, but it is not always true. Try this:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    handler.removeCallbacksAndMessages("ACTION_NAME")
    handler.postDelayed(runnable, "ACTION_NAME", 10_000) //if you want restart runnable
} else {
    handler.removeCallbacksAndMessages(null)
    handler.postDelayed(runnable, 10_000) //if you want restart runnable
}
冬天的雪花 2024-11-12 04:40:09

删除特定可运行对象

handler.removeCallbacks(yourRunnable)

删除所有可运行对象

handler.removeCallbacksAndMessages(null)

To remove specific runnable

handler.removeCallbacks(yourRunnable)

To remove all runnables

handler.removeCallbacksAndMessages(null)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文