Как удалить все обратные вызовы из обработчика?

У меня есть обработчик из моего подэтапа, который вызывался основным действием Этот обработчик используется подклассами для 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):

  1. удалить с помощью обратного вызова (и токена)
  2. удалить с помощью message.what (и токен)
  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 выполняет настоящую работу:

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;
        }
    }
}