Как удалить все обратные вызовы из обработчика? - PullRequest
205 голосов
/ 04 мая 2011

У меня есть Обработчик из моего подэтапа, который был вызван основным Активом .Этот обработчик используется подклассами для postDelay некоторых Runnables, и я не могу ими управлять.Теперь в событии onStop мне нужно удалить их перед завершением Деятельности (как-то я звонил finish(), но он все равно вызывался снова и снова).Есть ли способ удалить все обратные вызовы из обработчика?

Ответы [ 6 ]

483 голосов
/ 13 апреля 2012

По моему опыту, это прекрасно сработало!

handler.removeCallbacksAndMessages(null);

В документах для removeCallbacksAndMessages написано ...

Удалите все ожидающие сообщения обратных вызовов и отправленных сообщений, чей объект является токеном. Если токен null, все обратные вызовы и сообщения будут удалены.

18 голосов
/ 04 мая 2011

Для любого конкретного экземпляра 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 s, когда они публикуются / исполняются ... или искать другую парадигму для передачи ваших сообщений между каждым Activity

HopeЭто помогает!

8 голосов
/ 04 мая 2011

Если у вас нет ссылок Runnable, при первом обратном вызове получите объект сообщения и используйте removeCallbacksAndMessages () для удаления всех связанных обратных вызовов.

5 голосов
/ 20 января 2015

Определите новый обработчик и работоспособный:

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);
2 голосов
/ 14 декабря 2016

На самом деле здесь есть маленький, но очень важный момент.Вы должны определить 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 экземпляры.Таким образом, вы потеряли необходимые ссылки, которые принадлежат обработчик и 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 том, что вы используете '.

1 голос
/ 29 ноября 2018

Как сказал josh527, handler.removeCallbacksAndMessages(null); может работать.
Но почему?
Если вы посмотрите на исходный код, вы сможете понять его более четко. Существует 3 типа методов для удаления обратных вызовов / сообщений из обработчика (MessageQueue):

  1. удалить с помощью обратного вызова (и токена)
  2. удалить сообщением. 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;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...