Информационная архитектура

В 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

  1. Найдите XML-файлы настроек для исходной и целевой страниц. Эту информацию можно получить с помощью метода getPreferenceScreenResId() страницы.
  2. Удалить настройки из XML исходной страницы.
  3. Добавьте настройки в XML-код целевой страницы.
  4. Удалите PreferenceController для этого параметра из реализации Java исходной страницы. Обычно он находится в createPreferenceControllers() . Контроллер можно объявить непосредственно в XML.

    Примечание : у настройки может не быть PreferenceController .

  5. Создайте экземпляр PreferenceController в createPreferenceControllers() целевой страницы. Если PreferenceController определён в XML на старой странице, определите его также в XML для новой страницы.

Динамический ход в Android 9

  1. Узнайте, к какой категории относятся исходная и целевая страницы. Эту информацию можно найти в DashboardFragmentRegistry .
  2. Откройте файл AndroidManifest.xml , содержащий параметр, который необходимо переместить, и найдите запись Activity, представляющую этот параметр.
  3. Задайте значение метаданных активности для com.android.settings.category на основе ключа категории новой страницы.

Статическое перемещение в релизах Android 8.x

  1. Найдите XML-файлы настроек для исходной страницы и целевой страницы.
  2. Эту информацию можно получить с помощью метода getPreferenceScreenResId() страницы.
  3. Удалить настройки в XML исходной страницы.
  4. Добавьте настройки в XML целевой страницы.
  5. Удалите PreferenceController для этого параметра в реализации Java исходной страницы. Обычно он находится в getPreferenceControllers() .
  6. Примечание: возможно, у настройки нет PreferenceController .

  7. Создайте экземпляр PreferenceController в getPreferenceControllers() целевой страницы.

Динамический ход в релизах Android 8.x

  1. Узнайте, к какой категории относятся исходная и целевая страницы. Эту информацию можно найти в DashboardFragmentRegistry .
  2. Откройте файл AndroidManifest.xml , содержащий параметр, который необходимо переместить, и найдите запись Activity, представляющую этот параметр.
  3. Измените значение метаданных активности для com.android.settings.category , задайте точку значения для ключа категории новой страницы.

Создать новую настройку на странице

Если параметр статически указан в XML-файле настроек исходной страницы, выполните статическую процедуру, описанную ниже. В противном случае выполните динамическую процедуру.

Создать статическую настройку

  1. Найдите XML-файлы настроек для страницы. Эту информацию можно получить с помощью метода getPreferenceScreenResId() страницы.
  2. Добавьте новый элемент «Preference» в XML-файл. Убедитесь, что он имеет уникальный android:key .
  3. Определите 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"/>

Создать динамическое предпочтение

  1. Узнайте, к какой категории относятся исходная и целевая страницы. Эту информацию можно найти в DashboardFragmentRegistry .
  2. Создайте новую активность в AndroidManifest
  3. Добавьте необходимые метаданные в новую Activity для определения настройки. Задайте для метаданных com.android.settings.category то же значение, что и в шаге 1.

Создать новую страницу

  1. Создайте новый фрагмент, унаследованный от DashboardFragment .
  2. Определите его категорию в DashboardFragmentRegistry .

    Примечание: Этот шаг необязателен. Если вам не нужны динамические настройки на этой странице, указывать ключ категории не нужно.

  3. Следуйте инструкциям по добавлению необходимых настроек для этой страницы. Подробнее см. в разделе «Реализация» .

Проверка

  • Запустите робоэлектрические тесты в настройках. Все существующие и новые тесты должны пройти успешно.
  • Создайте и установите настройки, затем вручную откройте изменяемую страницу. Страница должна обновиться немедленно.