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?
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.
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 Runnable
s as they are posted/executed...or look at another paradigm for passing your messages between each Activity
Hope that Helps!
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.
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);
Actually there is a little but so important point here.
You should define a Handler
and a Runnable
just first time. Actually removeCallbacks(runnable)
works correctly but if you define them each times, you may not handle them.
False 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.
True 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'.
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):
- remove by callback (and token)
- remove by message.what (and token)
- 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;
}
}
}
来源:https://stackoverflow.com/questions/5883635/how-to-remove-all-callbacks-from-a-handler