name="AppTheme"
parent="
Theme.AppCompat.Light.DarkActionBar
">
name="colorPrimary">@color/colorPrimary
name="colorPrimaryDark">@color/colorPrimaryDark
name="colorAccent">@color/colorAccent
name="AppTheme"
parent="Theme.AppCompat.Light.DarkActionBar">
name="StrongBeatBoxButton"
parent="@style/BeatBoxButton">
- bold
name="AppTheme"
parent="Theme.AppCompat.Light.DarkActionBar">
...
name="AppTheme"
parent="Theme.AppCompat
.Light.DarkActionBar
">
...
name="AppTheme"
parent="Theme.AppCompat">
name="colorPrimary">@color/
colorPrimaryred<
/item>
name="colorPrimaryDark">@color/
colorPrimary
Darkdark_red
name="colorAccent">@color/
colorAccentgray
item>
name="Theme.AppCompat"
parent="Base.Theme.AppCompat" />
Тема
Theme.AppCompat
наследует
атрибуты
от
Base.Theme.AppCompat
. Интересно, что
Theme.AppCompat
не
переопределяет никакие атрибуты, а только содержит ссылку
на своего родителя.
Щелкните мышью по
Base.Theme.AppCompat
с нажатой
клавишей (
Ctrl
). Android Studio сообщит, что тема уточняется
по ресурсам. Существует несколько разных версий этой темы в
зависимости от используемой версии Android.
name="Base.Theme.AppCompat"
parent="Base.V7.Theme.AppCompat">
name="Base.V7.Theme.AppCompat"
parent="Platform.AppCompat">
-
androidx.appcompat.app.AppCompatVie
wInflater
- false
- true
name="windowActionBarOverlay">false
name="Platform.AppCompat"
parent="android:Theme.Holo">
name="android:windowNoTitle">true
name="android:windowActionBar">false
- ?
attr/buttonBarStyle
- ?
attr/buttonBarButtonStyle
name="android:borderlessButtonStyle">?
attr/borderlessButtonStyle
...
name="Platform.AppCompat"
parent="android:Theme.Holo">
...
...
name="android:windowBackground">@color/backgrou
nd_material_dark
name="AppTheme"
parent="Theme.AppCompat">
- @color/red
name="colorPrimaryDark">@color/dark_red
- @color/gray
-
name="android:windowBackground">@color/soothing
_blue
name="Base.V7.Theme.AppCompat"
parent="Platform.AppCompat">
...
name="buttonStyle">@style/Widget.AppCompat.Butt
on
name="buttonStyleSmall">@style/Widget.AppCompat
.Button.Small
...
name="Widget.AppCompat.Button"
parent="Base.Widget.AppCompat.Button"/>
Стиль
Widget.AppCompat.Button
самостоятельно никакие
атрибуты не определяет. Чтобы просмотреть его содержимое,
перейдите к его родителю. Вы увидите, что базовый стиль
существует
в
двух
версиях.
Выберите
версию
values/values.xml
.
name="Base.Widget.AppCompat.Button"
parent="android:Widget">
name="android:background">@drawable/abc_btn_def
ault_mtrl_shape
- ?
android:attr/textAppearanceButton
- 48dip
- 88dip
- true
- true
name="android:gravity">center_vertical|center_h
orizontal
name="AppTheme"
parent="Theme.AppCompat">
name="colorPrimary">@color/red
name="AppTheme"
parent="Theme.AppCompat">
name="colorPrimary">@color/red
name="colorPrimaryDark">@color/dark_red
name="colorAccent">@color/gray
name="android:windowBackground">@color/soothing
_blue
name="BeatBoxButton"
parent="Widget.AppCompat.Button">
name="android:background">@color/dark_bluem>
name="Platform.AppCompat"
parent="android:Theme.Holo">
...
name="AppTheme"
parent="Theme.AppCompat">
...
name="BeatBoxButton"
parent="Widget.AppCompat.Button">
name="AppTheme"
parent="Theme.AppCompat">
...
name="BeatBoxButton"
parent="Widget.AppCompat.Button">
name="android:background">@drawable/button_beat
_box_normal
-
name="android:background">@drawable/button_beat
_box
Листинг 25.12. Подключение ThumbnailDownloader
(PhotoGalleryFragment.kt)
class PhotoGalleryFragment : Fragment() {
...
private inner class PhotoAdapter(private
val galleryItems: List)
: RecyclerView.Adapter
() {
...
override fun onBindViewHolder(holder:
PhotoHolder, position: Int) {
val galleryItem =
galleryItems[position]
...
thumbnailDownloader.queueThumbnail(
holder, galleryItem.url)
}
}
}
Еще раз запустите PhotoGallery и проверьте содержимое
панели
Logcat
. При прокрутке
RecyclerView
вы должны
увидеть на панели
Logcat
строки, сигнализирующие о том, что
ThumbnailDownloader
получает каждый ваш запрос на
загрузку. Стена фотографий Билла пока никуда не делась.
Теперь, когда у вас запущен
HandlerThread
, следующим
шагом будет общение между основным потоком вашего
приложения и вашим новым фоновым потоком.
Сообщения и обработчики сообщений
Специализированный поток будет загружать фотографии, но
как он будет взаимодействовать с адаптером
RecyclerView
для их отображения, если не может напрямую обращаться к
главному потоку? (Не забывайте, что фоновым потокам не
разрешается выполнять код, в результате которого изменяется
выводимый на экран контент, так как это разрешено только
основному потоку. А основной поток не может выполнять
долгосрочные задачи — это разрешено только фоновому
потоку.)
Вспомните пример с обувным магазином и двумя
продавцами-Флэшами. Фоновый Флэш завершил свой
телефонный разговор с поставщиком, и теперь ему нужно
сообщить Главному Флэшу о том, что обувь была заказана. Если
Главный Флэш занят, Фоновый Флэш не может сделать это
немедленно. Ему придется подождать у стойки и перехватить
Главного Флэша в свободный момент. Такая схема работает, но
не слишком эффективно.
Лучше дать каждому Флэшу по почтовому ящику. Фоновый
Флэш пишет сообщение о том, что обувь заказана, и кладет его
в ящик Главного Флэша. Главный Флэш делает то же самое,
когда он хочет сообщить Фоновому Флэшу о том, что какой-то
товар закончился.
Идея почтового ящика чрезвычайно полезна. Возможно, у
продавца имеется задача, которая должна быть выполнена
скоро, но не прямо сейчас. В таком случае он кладет сообщение
в свой почтовый ящик и обрабатывает его в свободное время.
В Android такой «почтовый ящик», используемый потоками,
называется очередью сообщений (message queue). Поток,
работающий с использованием очереди сообщений, называется
циклом сообщений (message loop); он снова и снова проверяет
новые сообщения, которые могли появиться в очереди (рис.
25.2).
Цикл сообщений состоит из потока и объекта
Looper
,
управляющего очередью сообщений потока.
Do'stlaringiz bilan baham: |