В 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-файл содержит статический список настроек для отображения.
Динамические настройки
Динамический элемент представляет собой плитку с намерением, ведущим к внешней или внутренней Activity. Обычно намерение ведет к другой странице настроек. Например, элемент настроек «Google» на главной странице настроек является динамическим элементом. Динамические элементы определяются в AndroidManifest (обсуждается ниже) и загружаются через FeatureProvider (определенный как DashboardFeatureProvider ).
Динамические настройки более ресурсоемки, чем статические, поэтому обычно разработчикам следует реализовывать настройку как статическую. Однако динамическая настройка может быть полезна, если выполняется хотя бы одно из следующих условий:
- Данная настройка не реализована напрямую в приложении «Настройки» (например, путем внедрения настройки, реализованной в приложениях производителя/оператора связи).
- Эта настройка должна отображаться на главной странице настроек.
- У вас уже есть Activity для этой настройки, и вы не хотите добавлять дополнительную статическую конфигурацию.
Чтобы настроить действие как динамический параметр, выполните следующие действия:
- Чтобы пометить действие как динамическую настройку, добавьте к нему intent-filter.
- Укажите приложению «Настройки», к какой категории оно относится. Категория является константой, определяемой в
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, какие элементы доступны во время поиска. В Android 8.x появился класс PreferenceController.
Объект 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() страницы.
- Добавьте новый элемент настроек в 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. - Создайте новое Activity в
AndroidManifest - Добавьте необходимые метаданные в новое Activity, чтобы определить настройку. Установите значение метаданных для
com.android.settings.categoryравным значению, определенному на шаге 1.
Создать новую страницу
- Создайте новый фрагмент, наследующий от
DashboardFragment. - Определите категорию в
DashboardFragmentRegistry.Примечание: Этот шаг необязателен. Если вам не нужны динамические настройки на этой странице, указывать ключ категории не требуется.
- Выполните следующие шаги для добавления необходимых настроек для этой страницы. Дополнительную информацию см. в разделе «Реализация» .
Валидация
- Запустите тесты robolectric в настройках. Все существующие и новые тесты должны пройти успешно.
- Создайте и установите настройки, затем вручную откройте страницу, которую вы хотите изменить. Страница должна обновиться немедленно.