已更新的信息架构

Android 8.0 为“设置”应用引入了全新的信息架构。新信息架构的目标是简化设置的整理方式,便于用户快速查找自定义 Android 设备所需的设置。

示例和源代码

“设置”中的大多数页面目前都是使用新框架实现的。一个很好的例子是 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 和 PreferenceController

frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java packages/apps/Settings/src/com/android/settings/core/PreferenceController.java

实现

建议设备制造商调整现有的“设置”信息架构,并根据需要插入其他设置页面以适应合作伙伴的特定功能。将偏好设置从旧页面(实现为 SettingsPreferencePage)移到新页面(使用 DashboardFragment 实现)可能很复杂。旧页面的偏好设置在实现时可能没有创建 PreferenceController。

因此将偏好设置移到 DashboardFragment 中时,合作伙伴需要创建一个 PreferenceController,并且先将代码移到控制器中,然后在新的 DashboardFragment 中对偏好设置实例化。重构过程相当简单,因为大部分操作只是移动现有代码。

完成重构后,原始设备制造商 (OEM) 应提交带有测试的补丁程序 CL 以将其更改合并到上游。

插件样式信息架构

每个设置项都作为偏好设置进行实现。可以轻松地将偏好设置从一个页面移到另一个页面。

为了方便移动多个设置,Android O 引入了包含设置项的插件样式托管方片段。设置项被建模为插件样式控制器。因此,设置页面由单个托管方片段和多个设置控制器构成。

DashboardFragment

这是插件样式偏好设置控制器的托管方。该片段继承自 PreferenceFragment,并具有用于放大和更新静态偏好设置列表与动态偏好设置列表的钩子。

静态偏好设置

静态偏好设置列表在 XML 中使用 标记定义。DashboardFragment 实现使用 getPreferenceScreenResId() 方法来定义哪个 XML 文件包含要显示的偏好设置静态列表。

动态偏好设置

动态项表示具有 intent 的图块,会引向外部或内部 Activity。通常,intent 会引向不同的设置页面。例如,“设置”首页中的“Google”设置项就是一个动态项。动态项在 AndroidManifest 中定义(参见下文),并通过 FeatureProvider(定义为 DashboardFeatureProvider)加载。

请注意,动态设置的负载高于静态配置的设置,因此通常开发者应将设置实现为静态设置。但是,在以下任一情况下,动态设置非常有用:

  • 设置未在“设置”应用中直接实现(例如,注入由 OEM/运营商应用实现的设置)。
  • 设置应显示在“设置”首页上。
  • 您已具有设置的 Activity,不想要实现额外的静态配置。

要将 Activity 配置为动态设置,您需要执行以下操作:

  • 将该 Activity 标记为动态设置。为此,只需将 intent 过滤器添加到该 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>

在呈现时,片段将请求在 AndroidManifest 中定义的静态 XML 和动态设置偏好设置列表。无论在哪个来源中加载设置,DashboardFragment 都通过 PreferenceController 管理每个设置的处理逻辑(参见下文)。然后,它们将以混合列表的形式显示在界面上。

PreferenceController

PreferenceController 包含与偏好设置互动的所有逻辑,包括显示/更新/编入搜索索引等。

相应地,PreferenceController 的接口具有 isAvailable()、displayPreference()、handlePreferenceTreeClicked() 等的 API。有关每个 API 的详细文档可以在相应接口类中找到。

在为片段安装偏好设置时,信息中心会提供一种在显示之前附加 PreferenceController 的方法。在安装时,控制器将连接到片段,以便将来的所有相关事件均发送到控制器。

DashboardFragment 将在屏幕中保留 PreferenceController 的列表。在片段的 onCreate() 中,将为 isAvailable() 方法调用所有控制器,如果其返回 true,将调用 displayPreference() 来处理显示逻辑。

使用 DashboardFragment

将偏好设置从页面 A 移到页面 B

如果偏好设置静态地列在原始页面的偏好设置 XML 文件中,请遵循下面的静态路径。否则,请遵循动态路径。

静态

  1. 查找原始页面和目标页面的偏好设置 XML 文件。
  2. 您可以从页面的 getPreferenceScreenResId() 方法中找到此信息。
  3. 移除原始页面的 XML 中的偏好设置。
  4. 将偏好设置添加到目标页面的 XML 中。
  5. 在原始页面的 Java 实现中移除此偏好设置的 PreferenceController。通常它在 getPreferenceController() 中。
  6. 注意:偏好设置可能没有 PreferenceController。
  7. 在目标页面的 getPreferenceController() 中实例化 PreferenceController。

动态

  1. 查找原始页面和目标页面托管的类别。您可以在 DashboardFragmentRegistry 中找到此信息。
  2. 打开包含您需要移动的设置的 AndroidManifest.xml 文件,并找到表示此设置的 Activity 条目。
  3. 更改该 Activity 的“com.android.settings.category”元数据值,将值设置为新页面的类别键。

在页面中创建新的偏好设置

如果偏好设置静态地列在原始页面的偏好设置 XML 文件中,请遵循下面的静态路径。否则,请遵循动态路径。

静态

  1. 找到页面的偏好设置 XML 文件。您可以从页面的 getPreferenceScreenResId() 方法中找到此信息。
  2. 在 XML 中添加一个新的偏好设置项。确保其具有独特的 android:key。
  3. 在页面的 getPreferenceControllers() 方法中为此偏好设置实例化一个 PreferenceController。
  4. 如果该偏好设置已存在于其他地方,则表示其可能已具有 PreferenceController。您可以重新使用该 PreferenceController,无需构建新的 PreferenceController。

动态

  1. 查找原始页面和目标页面托管的类别。您可以在 DashboardFragmentRegistry 中找到此信息。
  2. 在 AndroidManifest 中创建一个新的 Activity,并添加必要的元数据来定义设置。将“com.android.settings.category”的元数据值设置为与第 1 步中定义的值相同。

新建页面

  1. 创建一个继承自 DashboardFragment 的新片段。
  2. DashboardFragmentRegistry 中定义其类别。

    注意:此步骤是可选的。如果您在此页面中不需要任何动态偏好设置,则不需要提供类别键。

  3. 遵循添加此页面所需设置的步骤进行操作。

验证

  • 在“设置”中运行 robolectric 测试,所有现有测试和新测试都应通过。
  • 编译并安装“设置”,手动打开正在被修改的页面;该页面应立即更新。