資訊架構

Android 8.0 為「設定」應用程式導入了新的資訊架構,簡化設定的整理方式,讓使用者更輕鬆快速地找到設定,自訂 Android 裝置。 Android 9 導入了多項改良功能,提供更多設定功能,並簡化實作程序。

範例和來源

目前「設定」中的大多數頁面都是使用新架構實作。以 DisplaySettings 為例: packages/apps/Settings/src/com/android/settings/DisplaySettings.java

重要元件的檔案路徑如下:

  • CategoryKeypackages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
  • DashboardFragmentRegistrypackages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
  • DashboardFragmentpackages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java
  • AbstractPreferenceControllerframeworks/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 中例項化之前,將程式碼移至控制器。PreferenceController 需要的 API 會在其名稱中說明,並記錄在 Javadoc 中。

強烈建議您為每個 PreferenceController 新增單元測試。如果變更已提交至 Android 開放原始碼計畫,則必須進行單元測試。如要進一步瞭解如何編寫以 Robolectric 為基礎的測試,請參閱 Readme 檔案 packages/apps/Settings/tests/robotests/README.md

外掛程式風格的資訊架構

每個設定項目都會實作為偏好設定。偏好設定可輕鬆從一個頁面移至另一個頁面。

為方便移動多項設定,Android 8.0 導入了包含設定項目的外掛程式樣式主機片段。設定項目會以外掛程式樣式的控制器為模型。因此,設定頁面是由單一主機片段和多個設定控制器所建構。

DashboardFragment

DashboardFragment 是外掛程式樣式偏好設定控制器的主機。這個片段會從 PreferenceFragment 繼承,並提供擴展和更新靜態偏好設定清單和動態偏好設定清單的掛鉤。

靜態偏好設定

靜態偏好設定清單是使用 <Preference> 標記在 XML 中定義。DashboardFragment 實作項目會使用 getPreferenceScreenResId() 方法,定義要顯示靜態偏好設定清單的 XML 檔案。

動態偏好設定

動態項目代表具有意圖的資訊方塊,可導向外部或內部活動。意圖通常會導向其他設定頁面。舉例來說,設定首頁中的「Google」設定項目是動態項目。動態項目定義於 AndroidManifest (詳見下文),並透過 FeatureProvider (定義為 DashboardFeatureProvider) 載入。

動態設定比靜態設定更耗用資源,因此開發人員通常應將設定實作為靜態設定。不過,在下列任一情況下,動態設定可能很有用:

  • 設定並非直接在「設定」應用程式中實作 (例如插入由原始設備製造商 (OEM)/電信業者應用程式實作的設定)。
  • 設定應會顯示在「設定」首頁。
  • 您已為設定建立活動,且不想實作額外的靜態設定。

如要將「活動」設為動態設定,請按照下列步驟操作:

  • 在活動中新增意圖篩選器,將活動標示為動態設定。
  • 向「設定」應用程式說明該類別的用途。類別是 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 包含與偏好設定互動的所有邏輯,包括顯示、更新、搜尋索引等。

PreferenceController 的介面定義為 BasePreferenceController。舉例來說,請參閱 packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java 中的程式碼

BasePreferenceController 有多個子類別,每個子類別都會對應至「設定」應用程式預設支援的特定 UI 樣式。舉例來說,TogglePreferenceController 的 API 會直接對應使用者與切換式偏好設定 UI 的互動方式。

BasePreferenceController 具有 getAvailabilityStatus()displayPreference()handlePreferenceTreeClicked(), 等 API。如需各項 API 的詳細說明文件,請參閱介面類別。

實作 BasePreferenceController (及其子類別,例如 TogglePreferenceController) 時,建構函式簽章必須符合下列任一條件:

  • public MyController(Context context, String key) {}
  • public MyController(Context context) {}

將偏好設定安裝至片段時,資訊主頁會提供方法,在顯示時間前附加 PreferenceController。安裝時,控制器會連線至片段,因此日後所有相關事件都會傳送至控制器。

DashboardFragment 會在畫面上保留 PreferenceController 清單。在片段的 onCreate() 中,系統會為 getAvailabilityStatus() 方法叫用所有控制器,如果傳回 true,則會叫用 displayPreference() 來處理顯示邏輯。getAvailabilityStatus() 也很重要,可告知設定架構在搜尋期間可用的項目。

Android 8.x 版本中的 PreferenceController

PreferenceController 包含與偏好設定互動的所有邏輯,包括顯示、更新、搜尋索引等。

對應偏好設定互動, PreferenceController 的介面具有 isAvailable() displayPreference()handlePreferenceTreeClicked() 等 API。如需各項 API 的詳細說明文件,請參閱介面類別。

將偏好設定安裝至片段時,資訊主頁會提供方法,在顯示時間前附加 PreferenceController。安裝時,控制器會連線至片段,因此日後所有相關事件都會傳送至控制器。

DashboardFragment 會在畫面上保留 PreferenceControllers 清單。在片段的 onCreate() 中,系統會為 isAvailable() 方法叫用所有控制器,如果該方法傳回 true,系統就會叫用 displayPreference() 來處理顯示邏輯。

使用 DashboardFragment

將偏好設定從 A 頁面移至 B 頁面

如果偏好設定靜態列於原始頁面的偏好設定 XML 檔案中,請按照下方 Android 版本適用的靜態移動程序操作。否則,請按照 Android 版本的動態遷移程序操作。

Android 9 中的靜態移動

  1. 找出原始網頁和目標網頁的偏好設定 XML 檔案。您可以透過頁面的 getPreferenceScreenResId() 方法取得這項資訊。
  2. 從原始網頁的 XML 中移除偏好設定。
  3. 在目的地網頁的 XML 中新增偏好設定。
  4. 從原始頁面的 Java 實作中,移除這個偏好設定的 PreferenceController。通常位於 createPreferenceControllers()。控制器可以直接在 XML 中宣告。

    注意:偏好設定可能沒有 PreferenceController

  5. 在到達網頁的 createPreferenceControllers() 中,例項化 PreferenceController。如果舊網頁的 XML 中定義了 PreferenceController,請在新網頁的 XML 中也定義該項目。

Android 9 中的動態移動

  1. 找出原始網頁和到達網頁所屬的類別。你可以在 DashboardFragmentRegistry 中查看這項資訊。
  2. 開啟包含要移動設定的 AndroidManifest.xml 檔案,然後找出代表這項設定的活動項目。
  3. com.android.settings.category 的活動中繼資料值設為新網頁的類別鍵。

Android 8.x 版本中的靜態移動

  1. 找出原始網頁和到達網頁的偏好設定 XML 檔案。
  2. 您可以使用頁面的 getPreferenceScreenResId() 方法取得這項資訊。
  3. 在原始網頁的 XML 中移除偏好設定。
  4. 將偏好設定新增至目的地網頁的 XML。
  5. 在原始頁面的 Java 實作中,移除這項偏好的 PreferenceController。通常位於 getPreferenceControllers()
  6. 注意:偏好設定可能沒有 PreferenceController

  7. 在到達網頁的 getPreferenceControllers() 中,例項化 PreferenceController

Android 8.x 版本中的動態移動

  1. 找出原始網頁和到達網頁所屬的類別。你可以在「DashboardFragmentRegistry」中找到這項資訊。
  2. 開啟包含要移動設定的 AndroidManifest.xml 檔案,然後找出代表這項設定的活動項目。
  3. 變更活動的 com.android.settings.category 中繼資料值,將值點設為新網頁的類別鍵。

在頁面中建立新的偏好設定

如果偏好設定靜態列於原始頁面的偏好設定 XML 檔案中,請按照下方的靜態程序操作。否則請按照動態程序操作。

建立靜態偏好設定

  1. 找出網頁的偏好設定 XML 檔案。您可以透過頁面的 getPreferenceScreenResId() 方法找到這項資訊。
  2. 在 XML 中新增偏好設定項目。確認該項目有專屬的 android:key
  3. 在頁面的 getPreferenceControllers() 方法中,為這項偏好設定定義 PreferenceController
    • 在 Android 8.x 和 Android 9 (選用) 中,請在網頁的 createPreferenceControllers() 方法中,為這項偏好設定例項化 PreferenceController

      如果其他位置已存在這項偏好設定,可能已有對應的 PreferenceController。您可以重複使用 PreferenceController,不必重新建構。

    • 從 Android 9 開始,您可以選擇在偏好設定旁邊的 XML 中宣告 PreferenceController。例如:
      <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. 按照步驟新增這個頁面所需的設定。詳情請參閱「導入」一節。

驗證

  • 在「設定」中執行 Robolectric 測試。所有現有和新的測試都應通過。
  • 建構並安裝「設定」,然後手動開啟要修改的頁面。 頁面應該會立即更新。