()
private val flickrFetchr = FlickrFetchr()
@Suppress("UNCHECKED_CAST")
@SuppressLint("HandlerLeak")
override fun onLooperPrepared() {
requestHandler = object : Handler() {
override fun handleMessage(msg:
Message) {
if (msg.what ==
MESSAGE_DOWNLOAD) {
val target = msg.obj as T
Log.i(TAG, "Got a request
for URL: ${requestMap[target]}")
handleRequest(target)
}
}
}
}
...
fun queueThumbnail(target: T, url: String)
{
...
}
private fun handleRequest(target: T) {
val url = requestMap[target] ?: return
val
bitmap
=
flickrFetchr.fetchPhoto(url) ?: return
}
}
При импорте библиотеки
Message
обязательно выберите из
предложенных опций
android.os.Message
.
Функция
Handler.handleMessage(...)
реализуется в
подклассе
Handler
внутри
onLooperPrepared()
. Функция
HandlerThread.onLooperPrepared()
вызывается до того,
как
Looper
впервые проверит очередь, поэтому она хорошо
подходит для создания реализации
Handler
.
В коде
Handler.handleMessage(...)
мы проверяем тип
сообщения, читаем значение
obj
(которое имеет тип
T
и
служит идентификатором для запроса) и передаем его функции
handleRequest(...)
.
(Вспомните,
что
Handler.handleMessage(...)
будет вызываться, когда
сообщение загрузки извлечено из очереди и готово к
обработке.)
Вся загрузка осуществляется в функции
handleRequest()
.
Мы проверяем существование URL-адреса, после чего передаем
его новому экземпляру знакомого класса
FlickrFetchr
. При
этом
используется
функция
FlickrFetchr.getUrlBytes(...)
,
которую
мы
так
предусмотрительно создали в этой главе.
Аннотация
@Suppress("UNCHECKED_CAST")
при проверке
сообщает Lint, что вы приводите
msg.obj
к типу
T
без
предварительной проверки того, относится ли
msg.obj
к этому
типу на самом деле. Это нормально, потому что вы
единственный разработчик, работающий с кодом PhotoGallery.
Вы сами управляете сообщениями, добавленными в очередь, и
знаете, что на данный момент все сообщения в очереди имеют
объектное поле, установленное в экземпляр
PhotoHolder
(которое
соответствует
T
,
указанному
в
ThumbnailDownloader
).
Реализация обработчика, описанная выше, технически
создает внутренний класс. Внутренние классы содержат ссылку
на
свой
внешний
класс
(в
данном
случае
ThumbnailDownloader
), что в свою очередь может привести к
утечке внешнего класса, если время жизни внутреннего класса
больше, чем предполагаемое время жизни внешнего класса.
Проблемы тут получаются только в том случае, если
обработчик прикреплен к объекту
Looper
основного потока.
Предупреждение
HandlerLeak
убирается
аннотацией
@SuppressLint("HandlerLeak")
, так как создаваемый
обработчик прикреплен к
looper
фонового потока. Если
вместо этого обработчик был прикреплен к
looper
основного
потока, то он может и не собирать мусор. Если бы произошла
утечка,
так
как
он
также
содержит
ссылку
на
ThumbnailDownloader
, ваше приложение также утеряло бы
экземпляр
ThumbnailDownloader
.
Блокировать предупреждения Lint нужно только в том
случае, если вы действительно понимаете, откуда взялось
предупреждение и почему его блокирование в данном
сценарии безопасно.
Запустите приложение PhotoGallery и проверьте на панели
LogCat
ваши подтверждающие команды регистрации.
Разумеется, запрос не будет полностью обработан до
момента назначения изображения в объекте
PhotoHolder
,
поступившем от
PhotoAdapter
. Однако эта операция
относится к пользовательскому интерфейсу, поэтому она
должна выполняться в главном потоке.
До
настоящего
момента
мы
ограничивались
использованием обработчиков и сообщений в одном потоке —
помещением сообщений в собственный почтовый ящик
ThumbnailDownloader
. В следующем разделе вы увидите, как
ThumbnailDownloader
использует
Handler
для отправки
запросов главному потоку.
Do'stlaringiz bilan baham: