Почему публикация и отмена работоспособности в представлении и обработчике приводят к разным последствиям? - PullRequest
6 голосов
/ 19 марта 2012

Я играл с Runnable s и обнаружил, что если вы postDelayed a Runnable на View, то удаление обратного вызова не будет работать, однако, если вы сделаете то же самое, но опубликуете Runnable на Handler, тогда удаление обратного вызова работает.

Почему эта работа (Runnable код run () никогда не выполняется):

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        // execute some code
    }
};

Handler handler = new Handler();
handler.postDelayed(runnable, 10000);
handler.removeCallbacks(runnable);

где это не так (Runnable код run () всегда выполняется)?:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        // execute some code
    }
};

View view = findViewById(R.id.some_view);
view.postDelayed(runnable, 10000);
view.removeCallbacks(runnable);

Ответы [ 3 ]

4 голосов
/ 19 марта 2012

Если View не прикреплено к окну, я вижу, что это происходит, благодаря тому, что выглядит как ошибка в Android.Тактически, поэтому, это может быть вопросом времени, убедившись, что вы не публикуете или не удаляете Runnable до тех пор, пока View не присоединится к окну.

Если у вас есть образецпроект, лежащий вокруг, который копирует эту проблему, я хотел бы взглянуть на это.В противном случае, я постараюсь сделать свой собственный, чтобы у меня было что-то, что я мог бы использовать для сообщения о предполагаемой ошибке.


ОБНОВЛЕНИЕ

Как упомянуто в комментариях, removeCallbacks() на более обычных виджетах работает, поэтому, похоже, это WebView -специфическая проблема, согласно примеру кода OP.

0 голосов
/ 07 апреля 2016

Глядя на ViewRootImpl.java , семантика View.removeCallbacks () кажется, по меньшей мере, неясной.

RunQueue.removeCallbacks просто удаляет Runnables из ArrayList. Смотри здесь .

Если RunQueue.executeActions вызывается перед removeCallbacks, тогда ArrayList очищается во всех случаях, что делает removeCallbacks запретом. Смотри здесь .

RunQueue.executeActions вызывается для каждого обхода .... См. здесь .

Так что, если я не пропущу что-то, View.removeCallbacks не будет работать, если произошел обход с тех пор, как вы позвонили View.post.

Я буду придерживаться @ james-wald комментария выше и не буду использовать View.post

0 голосов
/ 02 марта 2014

По разным причинам обработчик представления (view.getHandler ()) может быть не готов, когда вы хотите запустить анимацию.

Поэтому вам, вероятно, следует подождать, прежде чем назначить представление для вида.

Предполагая, что вы пытаетесь сделать это из Activity, вот код, который ждет, пока обработчик не станет доступным, прежде чем публиковать исполняемый файл:

private void assignRunnable(final View view, final Runnable runnable, final int delay)
{
  if (view.getHandler() == null) {
    // View is not ready, postpone assignment
    this.getView().postDelayed(new Runnable() {
      @Override
      public void run() {
        assignRunnable(view, runnable, delay);
      }
    }, 100);

    //Abort
    return;
  }

  //View is ready, assign the runnable
  view.postDelayed(runnable, delay);
}
...