У меня есть обработчик из моего подэтапа, который вызывался основным действием Этот обработчик используется подклассами для postDelay
некоторых Runnables, и я не могу ими управлять. Теперь, в событии onStop
, мне нужно удалить их перед завершением действия (каким-то образом я позвонил finish()
, но он все еще вызывается снова и снова). Есть ли способ удалить все обратные вызовы из обработчика?
Как удалить все обратные вызовы из обработчика?
Ответ 1
По моему опыту это работало отлично!
handler.removeCallbacksAndMessages(null);
В документах для removeCallbacksAndMessages указано...
Удалите все ожидающие сообщения обратных вызовов и отправленные сообщения, obj которых является токеном. Если токен
null
, все обратные вызовы и сообщения будут удалены.
Ответ 2
Для любого конкретного экземпляра 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
по мере их публикации/выполнения... или взглянуть на другую парадигму для передачи ваших сообщений между каждым Activity
Надеюсь, что это поможет!
Ответ 3
Если у вас нет ссылок Runnable, при первом обратном вызове получите obj сообщения и используйте removeCallbacksAndMessages() для удалить все связанные обратные вызовы.
Ответ 4
Определить новый обработчик и запустить:
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);
Ответ 5
Обратите внимание, что в области видимости класса необходимо определить 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()
до его вызова. Потому что каждый раз создает экземпляры new Handler
и new 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
том, что вы используете".
Ответ 6
Как сказал josh527
, handler.removeCallbacksAndMessages(null);
может работать.
Но почему?
Если вы посмотрите на исходный код, вы сможете понять его более четко.
Существует 3 типа методов для удаления обратных вызовов/сообщений из обработчика (MessageQueue):
- удалить с помощью обратного вызова (и токена)
- удалить с помощью message.what (и токен)
- удалить с помощью токена
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;
}
}
}