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

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 .

Информационная архитектура в стиле плагинов

Каждый элемент настроек реализован как Preference. Настройки можно легко перемещать с одной страницы на другую.

Чтобы упростить перемещение нескольких настроек, в Android 8.0 появился фрагмент хоста в стиле плагина, который содержит элементы настроек. Элементы настроек моделируются как контроллеры в стиле плагинов. Следовательно, страница настроек создается одним фрагментом хоста и несколькими контроллерами настроек.

DashboardFragment

DashboardFragment — это набор контроллеров предпочтений в стиле плагинов. Фрагмент наследуется от PreferenceFragment и имеет крючки для расширения и обновления как статических списков предпочтений, так и динамических списков предпочтений.

Статические настройки

Статический список предпочтений определяется в XML с помощью <Preference> . Реализация DashboardFragment использует метод getPreferenceScreenResId() , чтобы определить, какой файл XML содержит статический список настроек для отображения.

Динамические настройки

Динамический элемент представляет собой плитку с намерением, ведущую к внешнему или внутреннему действию. Обычно намерение ведет на другую страницу настроек. Например, элемент настройки «Google» на главной странице настроек является динамическим элементом. Динамические элементы определяются в AndroidManifest (обсуждается ниже) и загружаются через FeatureProvider (определяется как DashboardFeatureProvider ).

Динамические настройки имеют больший вес, чем статически настроенные, поэтому обычно разработчики должны реализовывать настройку как статическую. Однако динамическая настройка может быть полезна, если выполняется одно из следующих условий:

  • Этот параметр не реализуется напрямую в приложении «Настройки» (например, ввод параметра, реализованного в приложениях OEM/Carrier).
  • Параметр должен появиться на главной странице настроек.
  • У вас уже есть действие для настройки, и вы не хотите реализовывать дополнительную статическую конфигурацию.

Чтобы настроить действие как динамический параметр, выполните следующие действия:

  • Отметьте действие как динамическую настройку, добавив к действию фильтр намерений.
  • Сообщите приложению «Настройки», к какой категории оно относится. Категория — это константа, определенная в 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 в 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() для обработки логики отображения.

Использование фрагмента панели инструментов

Перемещение предпочтения со страницы 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. Добавьте необходимые метаданные в новое действие, чтобы определить настройку. Установите значение метаданных для com.android.settings.category на то же значение, которое было определено на шаге 1.

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

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

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

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

Проверка

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