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
- ค้นหาไฟล์ XML ของค่ากําหนดสําหรับหน้าต้นทางและหน้าปลายทาง คุณดูข้อมูลนี้ได้จากเมธอด
getPreferenceScreenResId()
ของหน้า - นำค่ากําหนดออกจาก XML ของหน้าเดิม
- เพิ่มค่ากําหนดลงใน XML ของหน้าปลายทาง
- นํา
PreferenceController
สําหรับค่ากําหนดนี้ออกจากการใช้งาน Java ของหน้าเดิม โดยทั่วไปจะอยู่ในcreatePreferenceControllers()
ตัวควบคุมอาจประกาศใน XML โดยตรงหมายเหตุ: ค่ากําหนดอาจไม่มี
PreferenceController
- สร้างอินสแตนซ์
PreferenceController
ในcreatePreferenceControllers()
ของหน้าปลายทาง หากมีการกําหนดPreferenceController
ใน XML ของหน้าเก่า ให้กําหนดใน XML ของหน้าใหม่ด้วย
การเคลื่อนไหวแบบไดนามิกใน Android 9
- ดูว่าหน้าต้นทางและหน้าปลายทางอยู่ในหมวดหมู่ใด คุณดูข้อมูลนี้ได้ใน
DashboardFragmentRegistry
- เปิดไฟล์
AndroidManifest.xml
ที่มีการตั้งค่าที่คุณต้องย้าย แล้วค้นหารายการกิจกรรมที่แสดงถึงการตั้งค่านี้ - ตั้งค่าข้อมูลเมตาของกิจกรรมสำหรับ
com.android.settings.category
เป็นคีย์หมวดหมู่ของหน้าใหม่
การเคลื่อนไหวแบบคงที่ในรุ่น Android 8.x
- ค้นหาไฟล์ XML ของค่ากําหนดสําหรับหน้าต้นทางและหน้าปลายทาง คุณดูข้อมูลนี้ได้จากเมธอด
- นำค่ากำหนดใน XML ของหน้าต้นฉบับออก
- เพิ่มค่ากําหนดลงใน XML ของหน้าปลายทาง
- นำ
PreferenceController
สำหรับค่ากําหนดนี้ออกในการนํา Java ไปใช้ในหน้าเว็บต้นฉบับ โดยทั่วไปจะอยู่ในgetPreferenceControllers()
- สร้างอินสแตนซ์
PreferenceController
ในgetPreferenceControllers()
ของหน้าปลายทาง
getPreferenceScreenResId()
ของหน้า
หมายเหตุ: ค่ากําหนดอาจไม่มี
PreferenceController
การย้ายแบบไดนามิกในรุ่น Android 8.x
- ดูว่าหน้าต้นทางและหน้าปลายทางอยู่ในหมวดหมู่ใด คุณดูข้อมูลนี้ได้ใน
DashboardFragmentRegistry
- เปิดไฟล์
AndroidManifest.xml
ที่มีการตั้งค่าที่คุณต้องย้าย แล้วค้นหารายการกิจกรรมที่แสดงถึงการตั้งค่านี้ - เปลี่ยนค่าข้อมูลเมตาของกิจกรรมสําหรับ
com.android.settings.category
โดยตั้งค่าจุดค่าเป็นคีย์หมวดหมู่ของหน้าเว็บใหม่
สร้างค่ากําหนดใหม่ในหน้าเว็บ
หากค่ากําหนดแสดงอยู่ในไฟล์ XML ของค่ากําหนดของหน้าเดิมแบบคงที่ ให้ทําตามขั้นตอนแบบคงที่ด้านล่าง หรือทำตามขั้นตอนแบบไดนามิก
สร้างค่ากําหนดแบบคงที่
- ค้นหาไฟล์ XML ของค่ากําหนดสําหรับหน้าเว็บ คุณดูข้อมูลนี้ได้จากเมธอด getPreferenceScreenResId() ของหน้า
- เพิ่มรายการค่ากําหนดใหม่ใน XML ตรวจสอบว่า
android:key
ของช่องไม่ซ้ำกัน -
กําหนด
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"/>
- ใน Android 8.x และ Android 9 (ไม่บังคับ) ให้สร้างอินสแตนซ์
สร้างค่ากําหนดแบบไดนามิก
- ดูว่าหน้าต้นทางและหน้าปลายทางอยู่ในหมวดหมู่ใด คุณดูข้อมูลนี้ได้ใน
DashboardFragmentRegistry
- สร้างกิจกรรมใหม่ใน
AndroidManifest
- เพิ่มข้อมูลเมตาที่จําเป็นลงในกิจกรรมใหม่เพื่อกําหนดการตั้งค่า ตั้งค่าค่าข้อมูลเมตาของ
com.android.settings.category
เป็นค่าเดียวกับที่กําหนดไว้ในขั้นตอนที่ 1
สร้างเพจใหม่
- สร้างส่วนย่อยใหม่โดยรับค่ามาจาก
DashboardFragment
- กำหนดหมวดหมู่ใน
DashboardFragmentRegistry
หมายเหตุ: ขั้นตอนนี้เป็นแบบไม่บังคับ หากไม่ต้องการค่ากําหนดแบบไดนามิกในหน้านี้ คุณก็ไม่จําเป็นต้องระบุคีย์หมวดหมู่
- ทำตามขั้นตอนเพื่อเพิ่มการตั้งค่าที่จําเป็นสําหรับหน้านี้ ดูข้อมูลเพิ่มเติมได้ที่ส่วนการใช้งาน
การตรวจสอบความถูกต้อง
- เรียกใช้การทดสอบ Robolectric ในการตั้งค่า การทดสอบที่มีอยู่และใหม่ทั้งหมดควรผ่าน
- บิลด์และติดตั้งการตั้งค่า จากนั้นเปิดหน้าเว็บที่จะแก้ไขด้วยตนเอง หน้าเว็บควรอัปเดตทันที