สถาปัตยกรรมข้อมูล

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 ได้ที่ไฟล์ packages/apps/Settings/tests/robotests/README.md

สถาปัตยกรรมข้อมูลสไตล์ปลั๊กอิน

รายการการตั้งค่าแต่ละรายการจะใช้เป็นค่ากําหนด คุณย้ายค่ากำหนดจากหน้าหนึ่งไปยังอีกหน้าหนึ่งได้โดยง่าย

Android 8.0 ได้เปิดตัวเศษส่วนของโฮสต์สไตล์ปลั๊กอินที่มีรายการการตั้งค่าเพื่อให้ย้ายการตั้งค่าหลายรายการได้ง่ายขึ้น รายการการตั้งค่าจะได้รับการโมเดลเป็นคอนโทรลเลอร์สไตล์ปลั๊กอิน ดังนั้น หน้าการตั้งค่าจึงสร้างขึ้นจากเศษส่วนของโฮสต์รายการเดียวและตัวควบคุมการตั้งค่าหลายรายการ

DashboardFragment

DashboardFragment คือโฮสต์ของตัวควบคุมค่ากำหนดสไตล์ปลั๊กอิน ข้อมูลโค้ดรับค่ามาจาก PreferenceFragment และมีฮุกเพื่อขยายและอัปเดตทั้งรายการค่ากําหนดแบบคงที่และรายการค่ากําหนดแบบไดนามิก

ค่ากําหนดแบบคงที่

รายการค่ากําหนดแบบคงที่จะกําหนดใน XML โดยใช้แท็ก <Preference> การใช้งาน DashboardFragment ใช้เมธอด getPreferenceScreenResId() เพื่อกำหนดว่าไฟล์ XML ใดมีรายการค่ากําหนดแบบคงที่ที่จะแสดง

ค่ากําหนดแบบไดนามิก

รายการแบบไดนามิกแสดงการ์ดที่มี Intent ซึ่งนําไปสู่กิจกรรมภายนอกหรือภายใน โดยปกติแล้ว Intent จะนําไปยังหน้าการตั้งค่าอื่น เช่น รายการการตั้งค่า "Google" ในหน้าแรกของการตั้งค่าเป็นรายการแบบไดนามิก ระบบจะกําหนดรายการแบบไดนามิกใน AndroidManifest (จะอธิบายด้านล่าง) และโหลดผ่าน FeatureProvider (กําหนดเป็น DashboardFeatureProvider)

การตั้งค่าแบบไดนามิกจะหนักกว่าการตั้งค่าที่กำหนดค่าแบบคงที่ ดังนั้นโดยทั่วไปนักพัฒนาแอปควรใช้การตั้งค่าแบบคงที่ อย่างไรก็ตาม การตั้งค่าแบบไดนามิกจะมีประโยชน์เมื่อเงื่อนไขใดๆ ต่อไปนี้เป็นจริง

  • การตั้งค่าไม่ได้ติดตั้งใช้งานในแอปการตั้งค่าโดยตรง (เช่น การแทรกการตั้งค่าที่แอป OEM/ผู้ให้บริการติดตั้งใช้งาน)
  • การตั้งค่าควรปรากฏในหน้าแรกของการตั้งค่า
  • คุณมีกิจกรรมสําหรับการตั้งค่าอยู่แล้วและไม่ต้องการใช้การกําหนดค่าแบบคงที่เพิ่มเติม

หากต้องการกําหนดค่ากิจกรรมเป็นการตั้งค่าแบบไดนามิก ให้ทําดังนี้

  • ทําเครื่องหมายกิจกรรมเป็นการตั้งค่าแบบไดนามิกด้วยการเพิ่มตัวกรอง Intent ลงในกิจกรรม
  • บอกแอปการตั้งค่าว่าแอปนั้นอยู่ในหมวดหมู่ใด หมวดหมู่นี้เป็นค่าคงที่ซึ่งกำหนดไว้ใน 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 (จะอธิบายด้านล่าง) จากนั้นระบบจะแสดงรายการดังกล่าวใน UI เป็นรายการแบบผสม

PreferenceController

การใช้งาน PreferenceController ใน Android 9 และ Android 8.x มีความแตกต่างกันตามที่อธิบายไว้ในส่วนนี้

PreferenceController ในรุ่น Android 9

PreferenceController มีตรรกะทั้งหมดในการโต้ตอบกับค่ากําหนด ซึ่งรวมถึงการแสดง การอัปเดต การจัดทําดัชนีการค้นหา ฯลฯ

อินเทอร์เฟซของ PreferenceController กำหนดเป็น BasePreferenceController เช่น ดูโค้ดใน packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java

BasePreferenceController มีหลายคลาสย่อย โดยแต่ละคลาสจะแมปกับสไตล์ UI ที่เฉพาะเจาะจงที่แอปการตั้งค่ารองรับโดยค่าเริ่มต้น ตัวอย่างเช่น TogglePreferenceController มี API ที่เชื่อมโยงโดยตรงกับวิธีที่ผู้ใช้ควรโต้ตอบกับ UI ค่ากําหนดแบบปุ่มเปิด/ปิด

BasePreferenceController มี API เช่น getAvailabilityStatus(), displayPreference(), handlePreferenceTreeClicked(), ฯลฯ เอกสารประกอบโดยละเอียดสำหรับแต่ละ API อยู่ในคลาสอินเทอร์เฟซ

ข้อจำกัดในการใช้งาน BasePreferenceController (และคลาสย่อย เช่น TogglePreferenceController) คือลายเซ็นคอนสตรัคเตอร์ต้องตรงกับอย่างใดอย่างหนึ่งต่อไปนี้

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

ขณะติดตั้งค่ากําหนดในข้อมูลโค้ด แดชบอร์ดจะมีวิธีการแนบ PreferenceController ก่อนเวลาแสดง เมื่อมีการติดตั้ง ตัวควบคุมจะเชื่อมต่อกับชิ้นส่วนเพื่อให้ระบบส่งเหตุการณ์ที่เกี่ยวข้องทั้งหมดในอนาคตไปยังตัวควบคุม

DashboardFragment เก็บรายการ PreferenceController ไว้ในหน้าจอ ที่ onCreate() ของข้อมูลโค้ดโค้ดจะเรียกใช้ตัวควบคุมทั้งหมดสําหรับเมธอด getAvailabilityStatus() และหากผลลัพธ์เป็น "จริง" ระบบจะเรียกใช้ displayPreference() เพื่อประมวลผลตรรกะการแสดงผล getAvailabilityStatus() ยังมีความจำเป็นในการบอกเฟรมเวิร์กการตั้งค่าว่ารายการใดบ้างที่พร้อมใช้งานระหว่างการค้นหา

PreferenceController ในรุ่น Android 8.x

PreferenceController มีตรรกะทั้งหมดในการโต้ตอบกับค่ากําหนด ซึ่งรวมถึงการแสดง การอัปเดต การจัดทําดัชนีการค้นหา ฯลฯ

อินเทอร์เฟซของ PreferenceController มี API isAvailable(), displayPreference(), handlePreferenceTreeClicked() ฯลฯ ซึ่งสอดคล้องกับการโต้ตอบกับค่ากําหนด ดูเอกสารประกอบโดยละเอียดเกี่ยวกับ API แต่ละรายการได้ในคลาสอินเทอร์เฟซ

ขณะติดตั้งค่ากําหนดในข้อมูลโค้ด แดชบอร์ดจะมีวิธีการแนบ PreferenceController ก่อนเวลาแสดง เมื่อมีการติดตั้ง ตัวควบคุมจะเชื่อมต่อกับชิ้นส่วนเพื่อให้ระบบส่งเหตุการณ์ที่เกี่ยวข้องทั้งหมดในอนาคตไปยังตัวควบคุม

DashboardFragment เก็บรายการ PreferenceControllers ไว้ในหน้าจอ ที่ onCreate() ของข้อมูลโค้ดแบบเป็นกลุ่ม ระบบจะเรียกใช้ตัวควบคุมทั้งหมดสําหรับเมธอด isAvailable() และหากผลลัพธ์เป็น "จริง" ระบบจะเรียกใช้ displayPreference() เพื่อประมวลผลตรรกะการแสดงผล

ใช้ DashboardFragment

ย้ายค่ากําหนดจากหน้า ก. ไปยัง ข.

หากค่ากำหนดแสดงอยู่ในไฟล์ 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 ที่มีการตั้งค่าที่คุณต้องย้าย แล้วค้นหารายการกิจกรรมที่แสดงถึงการตั้งค่านี้
  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 ที่มีการตั้งค่าที่คุณต้องย้าย แล้วค้นหารายการกิจกรรมที่แสดงถึงการตั้งค่านี้
  3. เปลี่ยนค่าข้อมูลเมตาของกิจกรรมสําหรับ com.android.settings.category โดยตั้งค่าจุดค่าเป็นคีย์หมวดหมู่ของหน้าเว็บใหม่

สร้างค่ากําหนดใหม่ในหน้าเว็บ

หากค่ากําหนดแสดงอยู่ในไฟล์ XML ของค่ากําหนดของหน้าเดิมแบบคงที่ ให้ทําตามขั้นตอนแบบคงที่ด้านล่าง หรือทำตามขั้นตอนแบบไดนามิก

สร้างค่ากําหนดแบบคงที่

  1. ค้นหาไฟล์ XML ของค่ากําหนดสําหรับหน้าเว็บ คุณดูข้อมูลนี้ได้จากเมธอด getPreferenceScreenResId() ของหน้า
  2. เพิ่มรายการค่ากําหนดใหม่ใน 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. ทำตามขั้นตอนเพื่อเพิ่มการตั้งค่าที่จําเป็นสําหรับหน้านี้ ดูข้อมูลเพิ่มเติมได้ที่ส่วนการใช้งาน

การตรวจสอบความถูกต้อง

  • เรียกใช้การทดสอบ Robolectric ในการตั้งค่า การทดสอบที่มีอยู่และใหม่ทั้งหมดควรผ่าน
  • บิลด์และติดตั้งการตั้งค่า จากนั้นเปิดหน้าเว็บที่จะแก้ไขด้วยตนเอง หน้าเว็บควรอัปเดตทันที