資訊架構

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 中例項化之前,將程式碼移至控制器。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 測試。所有現有和新的測試都應通過。
  • 建構並安裝「設定」,然後手動開啟要修改的頁面。 頁面應該會立即更新。