2012-03-19 1 views
6

Я играл примерно с Runnable с и обнаружил, что если вы postDelayedRunnable на View с последующим удалением обратного вызова не будут работать, однако, если вы делаете то же самое, но выкладывают Runnable на Handler с последующим удалением обратного вызов делает Работа.Почему публикация и аннулирование запуска в представлении View и Handler в разных версиях bahviour?

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

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

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

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

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); 
+1

Вы были проверять возвращаемое значение 'removeCallbacks()'? – CommonsWare

+0

Я этого не видел, не могли бы вы объяснить, как это может помочь? Я прочитал документацию, но не вижу, как это может помочь в моем примере выше. – Martyn

+2

'View.removeCallbacks()' всегда будет возвращать true; '(по крайней мере, на ICS-rest, вероятно, тоже) [см. Здесь] (http://grepcode.com/file/repository.grepcode.com/java/ext/ com.google.android/android/4.0.3_r1/android/view/View.java#8786) – zapl

ответ

4

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

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


UPDATE

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

+0

https://github.com/martynhaigh/RunnableCancelTest – Martyn

+0

@Martyn: Да, как я подозревал, «WebView» не прикреплен к окну в этот момент (например, 'getWindowToken()' возвращает 'null'), и поэтому вы собираетесь совершить поездку по этой ошибке в Android. Я напишу об этом в ближайшее время. Тем временем вам нужно будет использовать 'Handler' для надежного' removeCallbacks() '. – CommonsWare

+0

@Martyn: Кажется, проблема более тонкая, чем я думал. Я попытался воспроизвести вашу проблему с помощью кнопки 'Button', а' removeCallbacks() 'успешно, хотя кнопка' Button' не привязана к окну во время 'postDelayed()'. Теперь я предполагаю, что ваша трудность может быть более характерной для «WebView». Несмотря на это, вы, вероятно, должны просто использовать «Handler». – CommonsWare

0

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

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

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

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

Глядя на ViewRootImpl.java, семантику View.removeCallbacks() кажутся неясными, если не сказать больше.

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

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

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^