В 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
DashboardFragment
— это хранилище контроллеров настроек в стиле плагинов. Фрагмент наследует PreferenceFragment
и имеет хуки для расширения и обновления как статических, так и динамических списков настроек.
Статические настройки
Статический список настроек определяется в XML с помощью тега <Preference>
. Реализация DashboardFragment
использует метод getPreferenceScreenResId()
для определения XML-файла, содержащего статический список настроек для отображения.
Динамические настройки
Динамический элемент представляет собой плитку с намерением, ведущим к внешнему или внутреннему действию. Обычно намерение ведёт на другую страницу настроек. Например, элемент настройки «Google» на главной странице настроек — это динамический элемент. Динамические элементы определяются в AndroidManifest
(обсуждается ниже) и загружаются через FeatureProvider
(определяемый как DashboardFeatureProvider
).
Динамические настройки более «тяжелы», чем статически настроенные, поэтому обычно разработчикам следует реализовывать их как статические. Однако динамические настройки могут быть полезны, если выполняется любое из следующих условий:
- Настройка не реализована напрямую в приложении «Настройки» (например, путем внедрения настройки, реализованной приложениями OEM/оператора).
- Настройка должна появиться на главной странице настроек.
- У вас уже есть Activity для настройки и вы не хотите реализовывать дополнительную статическую конфигурацию.
Чтобы настроить 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>
Во время рендеринга фрагмент запросит список настроек Preferences как из статического XML, так и из динамических настроек, определённых в AndroidManifest
. Независимо от того, определены ли PreferenceController
в коде Java или в XML, DashboardFragment
управляет логикой обработки каждой настройки через 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()
также важен для того, чтобы сообщать фреймворку настроек, какие элементы доступны при поиске. 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
.Примечание: Этот шаг необязателен. Если вам не нужны динамические настройки на этой странице, указывать ключ категории не нужно.
- Следуйте инструкциям по добавлению необходимых настроек для этой страницы. Подробнее см. в разделе «Реализация» .
Проверка
- Запустите робоэлектрические тесты в настройках. Все существующие и новые тесты должны пройти успешно.
- Создайте и установите настройки, затем вручную откройте изменяемую страницу. Страница должна обновиться немедленно.