根据我的经验,调用这个函数非常好用!
handler.removeCallbacksAndMessages(null);
从removeCallbacksAndMessages的文档中可以看到...
删除所有等待执行的回调函数和发送的消息,它们的obj是token。 如果token为
null
,那么所有的回调和消息都将被删除。
对于任何特定的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)
移除所有待处理的回调。Handler
的整个MessageQueue
,即使你请求与它关联的MessageQueue
对象,因为添加和移除项目的方法的访问权限是包可见的(只有android.os包内的类可以调用它们)。你可能需要创建一个细小的Handler
子类来管理在发布/执行时的Runnable
列表...或者考虑另一种范例来在每个Activity
之间传递你的消息。定义一个新的处理程序和可运行对象:
private Handler handler = new Handler(Looper.getMainLooper());
private Runnable runnable = new Runnable() {
@Override
public void run() {
// Do what ever you want
}
};
延迟调用post:
handler.postDelayed(runnable, sleep_time);
从您的处理程序中移除回调函数:
handler.removeCallbacks(runnable);
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
实例。这样,您丢失了属于处理程序和可运行实例的必要引用。 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)
可以成功工作。
关键句子是“在使用的 Activity
或 Fragment
中将它们定义为全局变量”。
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负责实际工作:
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;
}
}
}
对我来说,这些解决方案都无效。但是我找到了一个有效的解决方案。
即使调用了 handler.removeCallbacksAndMessages(null)
,已经添加在处理程序队列中的可运行项仍将被执行。当我试图停止线程时,它会导致以下错误:
W/MessageQueue(6436): java.lang.RuntimeException: Handler (android.os.Handler) {416659f0} 将消息发送给一个已死亡的线程的处理程序
我的解决方案:
要删除所有回调,您需要引用可以存储在ArrayList中的所有可运行项。
private ArrayList<Runnable> runnableQueue=new ArrayList<Runnable>();
然后,每次想要发布可运行项时,请将其存储在数组中,然后使用handler.post()发布数组项。
private void postInHandler(){
@override
runnableQueue.add(new Runnable() {
public void run() {
//your code
}
});
//发布数组中的最后一项
handler.post(runnableQueue.get(runnableQueue.size()-1));
}
然后,要删除所有回调,请使用此方法,该方法将通过迭代数组来删除每个回调。
private void removeHandlerCallbacks(){
for(Runnable runnable:runnableQueue){
networkHandler.removeCallbacks(runnable,null);
}
runnableQueue.clear();
}
太好了!队列已清除。但是,在清除数组之后,我们必须确保在停止线程之前不再发布任何可运行项到处理程序。因此,您必须声明:
boolean 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();
}
就这些,现在队列已经清空,我们可以确定在清空队列后不会再有可运行的任务被加入。因此,可以安全地停止线程。
文档中说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
}
移除特定的可运行项
handler.removeCallbacks(yourRunnable)
为了移除所有可运行项
handler.removeCallbacksAndMessages(null)
removeCallbacksAndMessages(null)
无法删除我的某些回调。 当我想要停止接收回调时,我会调用handler.removeCallbacksAndMessages(null)
并将我的处理程序设置为 null,但是由于我仍然会得到回调,当我想要循环使用handler.postDelayed()
时就会遇到 NPE。 - SnakeryourHandler.removeCallbacks(yourRunnable)
是最可靠的方法。我今天仍在使用它。 - Snaker