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
Листинг 23.3. Получение информации у PackageManager
(NerdLauncherActivity.kt)
private const val TAG = "NerdLauncherActivity"
class
NerdLauncherActivity
:
AppCompatActivity() {
private lateinit var recyclerView:
RecyclerView
override fun onCreate(savedInstanceState:
Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_nerd_l
auncher)
recyclerView
=
findViewById(R.id.app_recycler_view)
recyclerView.layoutManager =
LinearLayoutManager(this)
setupAdapter()
}
private fun setupAdapter() {
val
startupIntent
=
Intent(Intent.ACTION_MAIN).apply {
addCategory(Intent.CATEGORY_LAUNCHE
R)
}
val
activities
=
packageManager.queryIntentActivities(startupInt
ent, 0)
Log.i(TAG, "Found ${activities.size}
activities")
}
}
Здесь мы создаем неявный интент с заданным действием
ACTION_MAIN
. Переменная
CATEGORY_LAUNCHER
добавлена в
категории интента.
Вызов
PackageManager.requestIntentActivities(Intent,Int)
возвращает список, содержащий
ResolveInfo
для всех activity,
у которых есть фильтр, соответствующий данному интенту. Вы
можете указать флаги для изменения результатов. Например,
флаг
PackageManager.GET_SHARED_LIBRARY_FILES
заставляет запрос включать в результаты дополнительные
данные (пути к библиотекам, которые связаны с каждым
приложением, удовлетворяющим требованиям). Здесь вы
передаете
0
, что указывает на то, что вы не хотите изменять
результаты.
Запустите приложение NerdLauncher и посмотрите в выводе
LogCat
,
сколько
приложений
вернул
экземпляр
PackageManager
(у нас при первом пробном запуске их было
30).
В CriminalIntent для отправки отчетов использовался
неявный интент. Чтобы представить на экране список выбора
приложений, мы создали неявный интент, упаковали его в
интент
выбора
и
отправили
ОС
вызовом
startActivity(Intent)
:
val intent = Intent(Intent.ACTION_SEND)
... // Создание и размещение дополнений
интентов
chooserIntent = Intent.createChooser(intent,
getString(R.string.send_report)
startActivity(chooserIntent)
Почему мы не используем этот подход здесь? Вкратце: дело
в том, что фильтр интентов
MAIN
/
LAUNCHER
может
соответствовать или не соответствовать неявному интенту
MAIN
/
LAUNCHER
,
отправленному
через
startActivity(Intent)
.
Оказывается, вызов
startActivity(Intent)
не означает
«Запустить activity, соответствующую этому неявному
интенту». Он означает «Запустить activity поумолчанию,
соответствующую этому неявному интенту». Когда вы
отправляете
неявный
интент
с
использованием
startActivityForResult(Intent)
(или
startActivity(...)
), ОС незаметно включает в интент
категорию
Intent.CATEGORY_DEFAULT
.
Таким образом, если вы хотите, чтобы фильтр интентов
соответствовал неявным интентам, отправленным через
startActivity(Intent)
, вы должны включить в этот фильтр
интентов категорию
DEFAULT
.
Activity с фильтром интентов
MAIN
/
LAUNCHER
является
главной точкой входа приложения, которому она принадлежит.
Для нее важно лишь то, что она является главной точкой входа
приложения, а является ли она главной точкой входа «по
умолчанию» — несущественно, поэтому она не обязана
включать категорию
CATEGORY_DEFAULT
.
Так как фильтры интентов
MAIN
/
LAUNCHER
могут не
включать
CATEGORY_DEFAULT
, надежность их соответствия
неявным
интентам,
отправленным
вызовом
start-
Activity(Intent)
,
не
гарантирована.
Поэтому
мы
используем интент для прямого запроса у
PackageManager
информации об activity с фильтром интентов
MAIN
/
LAUNCHER
.
Следующий шаг — отображение меток этих activity в списке
RecyclerView
экземпляра
NerdLauncherFragment
. Метка
( label) activity представляет собой отображаемое имя — нечто,
понятное пользователю. Если учесть, что эти activity относятся
к лаунчеру, такой меткой, скорее всего, должно быть имя
приложения.
Метки activity вместе с другими метаданными содержатся в
объектах
ResolveInfo
, возвращаемых
PackageManager
.
Сначала
отсортируйте
объекты
ResolveInfo
,
возвращаемые
PackageManager
, в алфавитном порядке меток,
получаемых
функцией
ResolveInfo.loadLabel
(PackageManager)
.
Do'stlaringiz bilan baham: |