Runnable успешно опубликован, но не запущен - PullRequest
24 голосов
/ 03 ноября 2010

В существующем проекте Android я столкнулся со следующим фрагментом кода (куда я вставил помет отладки)способ сделать вещи, не блокируя основной (UI) поток, при этом все еще устанавливая изображение в потоке UI после декодирования. (по крайней мере, по словам разработчиков Android) (что я проверил, зарегистрировав Thread.currentThread().getName() в разных местах)

Теперь иногда изображение просто не отображаетсяup, и stdout говорит только

I/System.out( 8066): bitmap: android.graphics.Bitmap@432f3ee8 img: android.widget.ImageView@4339d698
I/System.out( 8066): runnable posted

без каких-либо следов сообщений из Runnable.Итак, очевидно, что Runnable не run(), хотя img.post() возвращает true.Вытащить ImageView в onCreate() и объявить его final не помогает.

Я ничего не понимаю.Простая установка точечного рисунка напрямую, в то время как блокировка потока пользовательского интерфейса исправляет ситуацию, но я хочу сделать все правильно.Кто-нибудь понимает, что здесь происходит?

(пс. Это все наблюдалось на телефонах Android 1.6 и android-3 sdk)

Ответы [ 6 ]

56 голосов
/ 05 мая 2012

Если вы посмотрите документы для View.post, то есть некоторая соответствующая информация:

Этот метод можно вызывать извне потока пользовательского интерфейса, только когда этот вид прикреплен к окну.

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

Как уже упоминалось, вы можете использовать Activity.runOnUiThread или предоставить свой собственный обработчик. Однако, если вы хотите сделать это непосредственно из самого View, вы можете просто получить обработчик View:

view.getHandler().post(...);

Это особенно полезно, если у вас есть пользовательское представление, которое включает в себя какую-то фоновую загрузку. Также добавлен бонус, заключающийся в том, что вам не нужно создавать новый отдельный обработчик.

10 голосов
/ 22 августа 2013

Я расширил ImageView класс, чтобы решить эту проблему.Я собираю исполняемые файлы, переданные для публикации, пока представление не прикреплено к окну, а в onAttachedToWindow сообщение собрано.

7 голосов
/ 03 ноября 2010

Я думаю, что проблема в том, что вы обновляете пользовательский интерфейс (ImageView) отдельным потоком, который не является потоком пользовательского интерфейса.Пользовательский интерфейс может быть обновлен только потоком пользовательского интерфейса.

Вы можете решить эту проблему, используя Обработчик :

Handler uiHandler;

public void onCreate(){
    ...
    uiHandler = new Handler(); // This makes the handler attached to UI Thread
    ...
}

Затем замените:

if ( !img.post(new Runnable() {

на

uiHandler.post(new Runnable() {

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

Обработчик - довольно запутанная концепция, я также потратил часы на изучение, чтобы по-настоящему понять это;)

6 голосов
/ 03 ноября 2010

Я не вижу ничего явно плохого в том, что у вас там;вызов View.post () должен заставить его работать в потоке пользовательского интерфейса.Если ваша активность исчезла (возможно, из-за поворота экрана), то ваш ImageView не будет обновлен, но я все равно ожидаю, что в записи журнала будет указано «установка растрового изображения ...», даже если вы его не видите.

Я предлагаю попробовать следующее и посмотреть, имеет ли это значение:

1) Используйте Log.d (стандартный регистратор Android) вместо System.out

2) Passваш Runnable для Activity.runOnUiThread (), а не View.post ()

3 голосов
/ 17 июля 2014

Используйте следующий код, можете публиковать свой код в MainThread в любое время в любом месте, но не зависит от Context или Activity.Это может предотвратить view.getHandler() сбой или утомительные onAttachedToWindow() материалы и т. Д.

    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //TODO
        }
    });
1 голос
/ 12 июня 2013

У меня была такая же проблема, и использование view.getHandler () также не удалось, потому что обработчик не присутствовал.runOnUiThread () решил проблему.Предположительно, это действительно делает некоторые очереди, пока пользовательский интерфейс не будет готов.

Причиной для меня был вызов задачи загрузки значков в базовом классе, и результат возвращался так быстро, что основной класс не установил представление (getView() фрагмент).

Я немного подозреваю, что когда-нибудь это может произойти внезапно.Но теперь я готов к этому!Спасибо, ребята.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...