Раздувать вид в фоновом потоке - PullRequest
35 голосов
/ 14 июля 2011

У меня очень простой вопрос:

Возможно или невозможно накачать представление (не добавлять его в макет) в фоновом потоке (например, в doInBackground AsyncTask)?

Я знаю, что это возможно, потому что я реализовал большинство операций в своем приложении таким образом, и у меня никогда не было проблем, пока у меня не было этой проблемы на Galaxy S: Android: android.view.InflateException: Binary XML Строка файла № 13: Ошибка надувания класса в SAMSUNG Galaxy S

Мне сказали, что я должен не раздувать Views в фоновых потоках, но каковы конкретные причины и почему мой подход работает на большинстве устройств, но не в Galaxy S?

Ответы [ 3 ]

39 голосов
/ 14 июля 2011

LayoutInflater не делает никаких предположений о том, в каком потоке он работает. И ничего не упоминается об этом в его документации. Кроме того, его кодовые швы не зависят от потоков.

С другой стороны, представления, созданные LayoutInflater, могут создавать экземпляры Handler s в своих конструкторах. Ну, они, вероятно, не должны этого делать, но для них нет требования не создавать / использовать Handler s в своих конструкторах.

Я предполагаю, что Samsung Galaxy S имел некоторые модификации в EditText, которые каким-то образом инициировали создание Handler (согласно журналу отказов из вашего другого экземпляра вопроса GestureDetector был создан экземпляр, который, в свою очередь, создал новый Handler ). Хотя реализация по умолчанию не делает этого.


В целом, я бы сказал, что из-за явного требования для View s не использовать Handler s и Looper s в своих конструкторах, вы не можете предполагать, что накачка Views из потока не-UI безопасна ,

Вы можете создать HandlerThread и попробовать накачать View s внутри него. Но я бы сказал, что это очень рискованно, так как в примере с Samsung Galaxy S предполагается, что этот поток будет работать в течение жизни View и будет обрабатывать все сообщения, используя Looper. Что может привести к сбою позже.

13 голосов
/ 20 июля 2016

С последней поддержкой lib вы можете использовать android.support.v4.view.AsyncLayoutInflater для асинхронного раздувания представлений. Будьте осторожны, поскольку это может привести к раздуванию потока пользовательского интерфейса, если не будут выполнены определенные требования:

Для того чтобы макет был асинхронно накачан, у него должен быть родитель, для которого generateLayoutParams (AttributeSet) является потокобезопасным, и все представления, создаваемые как часть инфляции, не должны создавать никаких обработчиков или иным образом вызывать myLooper (). Если макет, который пытается быть раздутым, не может быть создан асинхронно по какой-либо причине, AsyncLayoutInflater автоматически откажется от раздувания в потоке пользовательского интерфейса.

3 голосов
/ 03 февраля 2014

Возможно или невозможно накачать представление (не добавлять его в макет) в фоновом потоке (например, в doInBackground AsyncTask)?

Возможно, да,Рекомендуемые?Нет. Как упомянуто в документации:

Таким образом, для однопоточной модели Android есть просто два правила:

  1. Не блокировать поток пользовательского интерфейса
  2. Не обращайтесь к инструментарию пользовательского интерфейса Android извне потока пользовательского интерфейса

через: Процессы и потоки

Обновление [02/06/ 19]:

Очевидно, в библиотеке поддержки есть инструмент для этого: AsyncLayoutInflater ( версия Jetpack ).Он был представлен в версии 24 примерно в 2016 году (через 2 года после моего ответа)

Но, как уже упоминалось в других ответах, будьте осторожны с этим инструментом, поскольку он может очень легко иметь неприятные последствия.

...