Android 8.0 представила новую информационную архитектуру для приложения «Настройки», чтобы упростить способ организации настроек и облегчить пользователям быстрый поиск настроек для настройки своих устройств Android. Android 9 представила некоторые улучшения, чтобы обеспечить большую функциональность настроек и более простую реализацию.
Примеры и источник
Большинство страниц в Настройках в настоящее время реализованы с использованием нового фреймворка. Хорошим примером является DisplaySettings: packages/apps/Settings/src/com/android/settings/DisplaySettings.java
Пути к файлам важных компонентов указаны ниже:
- CategoryKey :
packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
- DashboardFragmentRegistry :
packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
- DashboardFragment :
packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java
- AbstractPreferenceController :
frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
- BasePreferenceController (представлен в Android 9):
packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java
Выполнение
Производителям устройств рекомендуется адаптировать существующую архитектуру информации о настройках и вставлять дополнительные страницы настроек по мере необходимости для размещения функций, специфичных для партнеров. Перемещение настроек со страницы прежней версии (реализованной как SettingsPreferencePage
) на новую страницу (реализованную с помощью DashboardFragment
) может быть сложным. Настройки со страницы прежней версии, скорее всего, не реализованы с помощью PreferenceController
.
Поэтому при перемещении предпочтений со страницы прежних настроек на новую страницу вам необходимо создать PreferenceController
и переместить код в контроллер перед его инстанцированием в новом DashboardFragment
. API, которые требуются PreferenceController
, описаны в их названии и задокументированы в Javadoc.
Настоятельно рекомендуется добавить юнит-тест для каждого PreferenceController
. Если изменение отправляется в AOSP, то требуется юнит-тест. Чтобы получить больше информации о том, как писать тесты на основе Robolectric, см. файл readme packages/apps/Settings/tests/robotests/README.md
.
Информационная архитектура в стиле плагина
Каждый элемент настроек реализован как Предпочтение. Предпочтение можно легко переместить с одной страницы на другую.
Чтобы упростить перемещение нескольких настроек, в Android 8.0 появился фрагмент хоста в стиле плагина, содержащий элементы настроек. Элементы настроек моделируются как контроллеры в стиле плагина. Таким образом, страница настроек создается одним фрагментом хоста и несколькими контроллерами настроек.
Фрагмент панели инструментов
DashboardFragment
— это хост контроллеров предпочтений в стиле плагина. Фрагмент наследуется от PreferenceFragment
и имеет хуки для расширения и обновления как статических списков предпочтений, так и динамических списков предпочтений.
Статические настройки
Статический список предпочтений определяется в XML с помощью тега <Preference>
. Реализация DashboardFragment
использует метод getPreferenceScreenResId()
для определения того, какой XML-файл содержит статический список предпочтений для отображения.
Динамические предпочтения
Динамический элемент представляет собой плитку с намерением, ведущим к внешнему или внутреннему действию. Обычно намерение ведет на другую страницу настроек. Например, элемент настройки «Google» на домашней странице настроек является динамическим элементом. Динамические элементы определяются в AndroidManifest
(обсуждается ниже) и загружаются через FeatureProvider
(определяется как DashboardFeatureProvider
).
Динамические настройки более тяжеловесны, чем статически настроенные настройки, поэтому обычно разработчики должны реализовывать настройку как статическую. Однако динамическая настройка может быть полезна, когда выполняется любое из следующих условий:
- Настройка не реализована напрямую в приложении «Настройки» (например, путем внедрения настройки, реализованной приложениями OEM/оператора).
- Настройка должна появиться на главной странице настроек.
- У вас уже есть Activity для настройки, и вы не хотите реализовывать дополнительную статическую конфигурацию.
Чтобы настроить действие как динамическую настройку, выполните следующие действия:
- Отметьте действие как динамическую настройку, добавив к нему фильтр намерений.
- Сообщите приложению «Настройки», к какой категории оно принадлежит. Категория — это константа, определяемая в
CategoryKey
. - Необязательно: добавьте текст резюме при отображении настройки.
Вот пример, взятый из приложения «Настройки» для DisplaySettings
.
<activity android:name="Settings$DisplaySettingsActivity" android:label="@string/display_settings" android:icon="@drawable/ic_settings_display"> <!-- Mark the activity as a dynamic setting --> <intent-filter> <action android:name="com.android.settings.action.IA_SETTINGS" /> </intent-filter> <!-- Tell Settings app which category it belongs to --> <meta-data android:name="com.android.settings.category" android:value="com.android.settings.category.ia.homepage" /> <!-- Add a summary text when the setting is displayed --> <meta-data android:name="com.android.settings.summary" android:resource="@string/display_dashboard_summary"/> </activity>
Во время рендеринга фрагмент запросит список настроек как из статического XML, так и из динамических настроек, определенных в AndroidManifest
. Независимо от того, определены ли PreferenceController
в коде Java или в XML, DashboardFragment
управляет логикой обработки каждой настройки через PreferenceController
(обсуждается ниже). Затем они отображаются в пользовательском интерфейсе в виде смешанного списка.
PreferenceController
Существуют различия между реализацией PreferenceController
в Android 9 и Android 8.x, как описано в этом разделе.
PreferenceController в выпуске Android 9
PreferenceController
содержит всю логику для взаимодействия с предпочтениями, включая отображение, обновление, индексацию поиска и т. д.
Интерфейс PreferenceController
определен как BasePreferenceController
. Например, см. код в packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java
Существует несколько подклассов BasePreferenceController
, каждый из которых соответствует определенному стилю пользовательского интерфейса, который приложение «Настройки» поддерживает по умолчанию. Например, TogglePreferenceController
имеет API, который напрямую соответствует тому, как пользователь должен взаимодействовать с пользовательским интерфейсом на основе переключателей.
BasePreferenceController
имеет такие API, как getAvailabilityStatus()
, displayPreference()
, handlePreferenceTreeClicked(),
и т. д. Подробная документация по каждому API находится в классе интерфейса.
Ограничением на реализацию BasePreferenceController
(и его подклассов, таких как TogglePreferenceController
) является то, что сигнатура конструктора должна соответствовать одному из следующих значений:
-
public MyController(Context context, String key) {}
-
public MyController(Context context) {}
При установке предпочтения к фрагменту, панель инструментов предоставляет метод для присоединения PreferenceController
до времени отображения. Во время установки контроллер подключается к фрагменту, поэтому все будущие соответствующие события отправляются контроллеру.
DashboardFragment
хранит список PreferenceController
на экране. В onCreate()
фрагмента все контроллеры вызываются для метода getAvailabilityStatus()
, и если он возвращает true, displayPreference()
вызывается для обработки логики отображения. getAvailabilityStatus()
также важен для сообщения фреймворку Settings, какие элементы доступны во время поиска. PreferenceController в релизах Android 8.x
PreferenceController
содержит всю логику для взаимодействия с предпочтениями, включая отображение, обновление, индексацию поиска и т. д.
В соответствии с взаимодействиями предпочтений интерфейс PreferenceController
имеет API isAvailable()
, displayPreference()
, handlePreferenceTreeClicked()
и т. д. Подробную документацию по каждому API можно найти в классе интерфейса.
При установке предпочтения к фрагменту, панель инструментов предоставляет метод для присоединения PreferenceController
до времени отображения. Во время установки контроллер подключается к фрагменту, поэтому все будущие соответствующие события отправляются контроллеру.
DashboardFragment
хранит список PreferenceControllers
на экране. В onCreate()
фрагмента все контроллеры вызываются для метода isAvailable()
, и если он возвращает true, displayPreference()
вызывается для обработки логики отображения.
Использовать DashboardFragment
Переместить предпочтение со страницы A на страницу B
Если предпочтение статически указано в XML-файле предпочтений исходной страницы, следуйте процедуре статического перемещения для вашего выпуска Android ниже. В противном случае следуйте процедуре динамического перемещения для вашего выпуска Android.
Статическое перемещение в Android 9
- Найдите файлы XML предпочтений для исходной страницы и целевой страницы. Эту информацию можно найти в методе
getPreferenceScreenResId()
страницы. - Удалите настройки из XML исходной страницы.
- Добавьте предпочтение в XML-файл целевой страницы.
- Удалите
PreferenceController
для этого предпочтения из реализации Java исходной страницы. Обычно это вcreatePreferenceControllers()
. Контроллер может быть объявлен в XML напрямую.Примечание : у предпочтения может не быть
PreferenceController
. - Создайте экземпляр
PreferenceController
вcreatePreferenceControllers()
целевой страницы. ЕслиPreferenceController
определен в XML на старой странице, определите его также в XML для новой страницы.
Динамическое перемещение в Android 9
- Найдите, какую категорию размещает исходная и целевая страница. Эту информацию можно найти в
DashboardFragmentRegistry
. - Откройте файл
AndroidManifest.xml
, содержащий параметр, который необходимо переместить, и найдите запись Activity, представляющую этот параметр. - Установите значение метаданных действия для
com.android.settings.category
на новый ключ категории страницы.
Статическое перемещение в релизах Android 8.x
- Найдите XML-файлы настроек для исходной страницы и целевой страницы. Эту информацию можно найти в методе
- Удалите настройки в XML исходной страницы.
- Добавьте предпочтение в XML целевой страницы.
- Удалите
PreferenceController
для этого параметра в реализации Java исходной страницы. Обычно он находится вgetPreferenceControllers()
. - Создайте экземпляр
PreferenceController
вgetPreferenceControllers()
целевой страницы.
getPreferenceScreenResId()
страницы. Примечание: возможно, у настройки нет PreferenceController
.
Динамический ход в релизах Android 8.x
- Найдите, какую категорию размещает исходная и целевая страница. Эту информацию можно найти в
DashboardFragmentRegistry
. - Откройте файл
AndroidManifest.xml
, содержащий параметр, который необходимо переместить, и найдите запись Activity, представляющую этот параметр. - Измените значение метаданных действия для
com.android.settings.category
, установите точку значения на ключ категории новой страницы.
Создать новую настройку на странице
Если предпочтение статически указано в XML-файле предпочтений исходной страницы, следуйте статической процедуре ниже. В противном случае следуйте динамической процедуре.
Создать статическое предпочтение
- Найдите файлы XML настроек для страницы. Эту информацию можно найти в методе getPreferenceScreenResId() страницы.
- Добавьте новый элемент Preference в XML. Убедитесь, что он имеет уникальный
android:key
. - Определите
PreferenceController
для этого предпочтения в методеgetPreferenceControllers()
страницы.- В Android 8.x и, при необходимости, в Android 9 создайте экземпляр
PreferenceController
для этого предпочтения в методеcreatePreferenceControllers()
страницы.Если эта настройка уже существовала в других местах, возможно, для нее уже есть
PreferenceController
. Вы можете повторно использоватьPreferenceController
, не создавая новый. - Начиная с Android 9, вы можете выбрать объявление
PreferenceController
в XML рядом с предпочтением. Например:<Preference android:key="reset_dashboard" android:title="@string/reset_dashboard_title" settings:controller="com.android.settings.system.ResetPreferenceController"/>
- В Android 8.x и, при необходимости, в Android 9 создайте экземпляр
Создать динамическое предпочтение
- Найдите, какую категорию размещает исходная и целевая страница. Эту информацию можно найти в
DashboardFragmentRegistry
. - Создайте новую активность в
AndroidManifest
- Добавьте необходимые метаданные в новую Activity, чтобы определить настройку. Установите значение метаданных для
com.android.settings.category
на то же значение, что и определенное в шаге 1.
Создать новую страницу
- Создайте новый фрагмент, унаследованный от
DashboardFragment
. - Определите его категорию в
DashboardFragmentRegistry
.Примечание: Этот шаг необязателен. Если вам не нужны динамические настройки на этой странице, вам не нужно указывать ключ категории.
- Следуйте инструкциям по добавлению настроек, необходимых для этой страницы. Для получения дополнительной информации см. раздел Реализация .
Проверка
- Запустите robolectric тесты в настройках. Все существующие и новые тесты должны пройти.
- Создайте и установите Настройки, затем вручную откройте страницу, которую изменяете. Страница должна обновиться немедленно.