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 โปรดดูที่ไฟล์ readme packages/apps/Settings/tests/robotests/README.md
สถาปัตยกรรมข้อมูลสไตล์ปลั๊กอิน
รายการการตั้งค่าแต่ละรายการจะถูกนำไปใช้เป็นค่ากำหนด การตั้งค่าสามารถย้ายจากหน้าหนึ่งไปอีกหน้าหนึ่งได้อย่างง่ายดาย
เพื่อให้ง่ายต่อการย้ายการตั้งค่าหลายรายการ Android 8.0 ได้เปิดตัวส่วนโฮสต์แบบปลั๊กอินที่มีรายการการตั้งค่า รายการการตั้งค่าจำลองเป็นตัวควบคุมแบบปลั๊กอิน ดังนั้น หน้าการตั้งค่าจึงถูกสร้างขึ้นโดยส่วนโฮสต์เดียวและตัวควบคุมการตั้งค่าหลายตัว
แดชบอร์ดแฟรกเมนต์
DashboardFragment
เป็นโฮสต์ของตัวควบคุมการกำหนดค่าตามความชอบแบบปลั๊กอิน แฟรกเมนต์สืบทอดมาจาก PreferenceFragment
และมี hooks เพื่อขยายและอัปเดตทั้งรายการการกำหนดค่าตามความชอบแบบคงที่และรายการการกำหนดค่าตามความชอบแบบไดนามิก
การตั้งค่าแบบคงที่
รายการการกำหนดลักษณะแบบคงที่ถูกกำหนดไว้ใน XML โดยใช้แท็ก <Preference>
การใช้งาน 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
(ดังที่อธิบายไว้ด้านล่าง) จากนั้นจะแสดงใน UI เป็นรายการผสม
ตัวควบคุมการตั้งค่า
มีความแตกต่างระหว่างการใช้ 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
) คือลายเซ็น Constructor ต้องตรงกับรายการใดรายการหนึ่งต่อไปนี้:
-
public MyController(Context context, String key) {}
-
public MyController(Context context) {}
ขณะติดตั้งการกำหนดค่าตามความชอบให้กับแฟรกเมนต์ แดชบอร์ดจัดเตรียมวิธีการแนบ PreferenceController
ก่อนเวลาแสดงผล ณ เวลาติดตั้ง คอนโทรลเลอร์จะต่อสายเข้ากับแฟรกเมนต์ ดังนั้นเหตุการณ์ที่เกี่ยวข้องในอนาคตทั้งหมดจะถูกส่งไปยังคอนโทรลเลอร์
DashboardFragment
เก็บรายการ PreferenceController
ไว้ในหน้าจอ ที่ onCreate()
ของแฟรกเมนต์ คอนโทรลเลอร์ทั้งหมดจะถูกเรียกใช้สำหรับเมธอด getAvailabilityStatus()
และหากคืนค่าเป็น true แสดงว่า displayPreference()
จะถูกเรียกใช้เพื่อประมวลผลตรรกะการแสดงผล getAvailabilityStatus()
เป็นสิ่งสำคัญเช่นกันในการบอกกรอบงานการตั้งค่าว่ามีรายการใดบ้างที่พร้อมใช้งานระหว่างการค้นหา PreferenceController ใน Android 8.x เปิดตัว
PreferenceController
มีตรรกะทั้งหมดเพื่อโต้ตอบกับการตั้งค่า รวมถึงการแสดง การอัปเดต และการจัดทำดัชนีการค้นหา ฯลฯ
เพื่อให้สอดคล้องกับการโต้ตอบการตั้งค่า อินเทอร์เฟซของ PreferenceController
มี APIs isAvailable()
, displayPreference()
, handlePreferenceTreeClicked()
ฯลฯ เอกสารรายละเอียดเกี่ยวกับ API แต่ละรายการสามารถพบได้ในคลาสอินเทอร์เฟซ
ขณะติดตั้งการกำหนดค่าตามความชอบให้กับแฟรกเมนต์ แดชบอร์ดจัดเตรียมวิธีการแนบ PreferenceController
ก่อนเวลาแสดงผล ณ เวลาติดตั้ง คอนโทรลเลอร์จะต่อสายเข้ากับแฟรกเมนต์ ดังนั้นเหตุการณ์ที่เกี่ยวข้องในอนาคตทั้งหมดจะถูกส่งไปยังคอนโทรลเลอร์
DashboardFragment
เก็บรายการ PreferenceControllers
ไว้ในหน้าจอ ที่ onCreate()
ของแฟรกเมนต์ คอนโทรลเลอร์ทั้งหมดจะถูกเรียกใช้สำหรับเมธอด isAvailable()
และหากคืนค่าเป็น true ก็จะเรียกใช้ displayPreference()
เพื่อประมวลผลตรรกะการแสดงผล
การใช้ DashboardFragment
การย้ายการกำหนดลักษณะจากเพจ A ไปยัง B
หากค่ากำหนดแสดงอยู่ในไฟล์ 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 ในการตั้งค่า การทดสอบที่มีอยู่และการทดสอบใหม่ทั้งหมดควรผ่าน
- สร้างและติดตั้งการตั้งค่า จากนั้นเปิดเพจที่กำลังแก้ไขด้วยตนเอง เพจควรปรับปรุงทันที