ב-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 שנדרש מפורט בשם שלו ומתועד ב-Javadoc.PreferenceController
מומלץ מאוד להוסיף בדיקת יחידה לכל PreferenceController
.
אם השינוי נשלח ל-AOSP, נדרשת בדיקת יחידה.
מידע נוסף על כתיבת בדיקות שמבוססות על Robolectric זמין בקובץ ה-Readme packages/apps/Settings/tests/robotests/README.md
.
ארכיטקטורת מידע בסגנון פלאגין
כל פריט הגדרות מיושם כהעדפה. אפשר להעביר העדפה בקלות מדף אחד לדף אחר.
כדי להקל על העברת הגדרות שונות, ב-Android 8.0 הושק פלאגין מסוג host fragment שמכיל פריטי הגדרות. פריטי ההגדרות מוגדרים כפקדים בסגנון פלאגין. לכן, דף ההגדרות מורכב מקטע מארח יחיד וממספר בקרי הגדרות.
DashboardFragment
DashboardFragment
הוא המארח של בקרי העדפות בסגנון פלאגין.
הקטע מקבל בירושה מ-PreferenceFragment
ויש לו ווים להרחבה ולעדכון של רשימות העדפות סטטיות ורשימות העדפות דינמיות.
העדפות סטטיות
רשימת העדפות סטטית מוגדרת ב-XML באמצעות התג <Preference>
. הטמעה של DashboardFragment
משתמשת בשיטה getPreferenceScreenResId()
כדי להגדיר איזה קובץ XML מכיל את הרשימה הסטטית של ההעדפות שיוצגו.
העדפות דינמיות
פריט דינמי מייצג משבצת עם Intent, שמובילה לפעילות חיצונית או פנימית. בדרך כלל, הכוונה מובילה לדף הגדרות אחר. לדוגמה,
הפריט 'Google' בהגדרות דף הבית הוא פריט דינמי. פריטים דינמיים מוגדרים בAndroidManifest
(כפי שמוסבר בהמשך) ונטענים באמצעות FeatureProvider
(מוגדר כ
DashboardFeatureProvider
).
הגדרות דינמיות הן כבדות יותר מהגדרות שמוגדרות באופן סטטי, ולכן בדרך כלל מפתחים צריכים להטמיע את ההגדרה כהגדרה סטטית. עם זאת, ההגדרה הדינמית יכולה להיות שימושית אם מתקיים אחד מהתנאים הבאים:
- ההגדרה לא מוטמעת ישירות באפליקציית ההגדרות (למשל, לא מוחדרת הגדרה שמוטמעת על ידי אפליקציות של יצרן הציוד המקורי או של ספק הסלולר).
- ההגדרה אמורה להופיע בדף הבית של ההגדרות.
- כבר יש לכם פעילות להגדרה ואתם לא רוצים להטמיע את ההגדרה הסטטית הנוספת.
כדי להגדיר פעילות כהגדרה דינמית:
- כדי לסמן את הפעילות כהגדרה דינמית, מוסיפים intent-filter לפעילות.
- מציינים באפליקציית ההגדרות לאיזו קטגוריה היא שייכת. הקטגוריה היא קבועה, והיא מוגדרת ב-
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
יש הבדלים בין ההטמעה של PreferenceController
ב-Android 9 לבין ההטמעה ב-Android 8.x, כפי שמתואר בקטע הזה.
PreferenceController בגרסה 9 של Android
PreferenceController
מכיל את כל הלוגיקה שנדרשת לאינטראקציה עם ההעדפה, כולל הצגה, עדכון, יצירת אינדקס לחיפוש וכו'.
הממשק של PreferenceController
מוגדר כ-BasePreferenceController
. לדוגמה, אפשר לראות קוד ב-packages/apps/Settings/src/com/android/settings/core/
BasePreferenceController.java
יש כמה תתי-מחלקות של BasePreferenceController
, שכל אחת מהן ממופה לסגנון ממשק משתמש ספציפי שאפליקציית ההגדרות תומכת בו כברירת מחדל. לדוגמה, ל-TogglePreferenceController
יש API שמתאים ישירות לאופן שבו המשתמש צריך לקיים אינטראקציה עם ממשק משתמש של העדפות שמבוסס על מתג.
ל-BasePreferenceController
יש ממשקי API כמו getAvailabilityStatus()
, displayPreference()
, handlePreferenceTreeClicked(),
וכו'. תיעוד מפורט לכל API נמצא במחלקת הממשק.
מגבלה על הטמעה של BasePreferenceController
(ומחלקות המשנה שלו, כמו TogglePreferenceController
) היא שחתימת הבנאי חייבת להיות תואמת לאחת מהאפשרויות הבאות:
public MyController(Context context, String key) {}
public MyController(Context context) {}
במהלך התקנת העדפה לקטע, מרכז הבקרה מספק שיטה לצירוף PreferenceController
לפני זמן התצוגה. בזמן ההתקנה,
הבקר מחובר אל ה-Fragment כך שכל האירועים הרלוונטיים העתידיים
יישלחו אל הבקר.
DashboardFragment
שומר רשימה של PreferenceController
במסך. ב-onCreate()
של הפרגמנט, כל הבקרים מופעלים עבור השיטה getAvailabilityStatus()
, ואם היא מחזירה true, מופעלת השיטה displayPreference()
כדי לעבד את לוגיקת התצוגה.
getAvailabilityStatus()
חשוב גם כדי להגדיר את פריטי המסגרת של ההגדרות שזמינים במהלך החיפוש.
PreferenceController בגרסאות Android 8.x
PreferenceController
מכיל את כל הלוגיקה לאינטראקציה עם ההעדפה, כולל הצגה, עדכון, יצירת אינדקס לחיפוש וכו'.
בהתאם לאינטראקציות עם ההעדפות, לממשק
PreferenceController
יש ממשקי API isAvailable()
,
displayPreference()
, handlePreferenceTreeClicked()
וכו'.
תיעוד מפורט על כל API זמין במחלקת הממשק.
במהלך התקנת העדפה לקטע, מרכז הבקרה מספק שיטה לצירוף PreferenceController
לפני זמן התצוגה. בזמן ההתקנה,
הבקר מחובר אל ה-Fragment כך שכל האירועים הרלוונטיים העתידיים
יישלחו אל הבקר.
DashboardFragment
שומר רשימה של PreferenceControllers
במסך. ב-onCreate()
של הפרגמנט, כל בקרים מופעלים עבור השיטה isAvailable()
, ואם היא מחזירה true, מופעלת השיטה 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() של הדף.
- מוסיפים פריט Preference חדש ב-XML. צריך לוודא שיש לו
android:key
ייחודי. -
מגדירים
PreferenceController
להעדפה הזו בשיטתgetPreferenceControllers()
של הדף.- ב-Android 8.x ובאופן אופציונלי ב-Android 9,
יוצרים מופע של
PreferenceController
להעדפה הזו ב-methodcreatePreferenceControllers()
של הדף.אם ההעדפה הזו כבר קיימת במקומות אחרים, יכול להיות שכבר יש
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 בהגדרות. כל הבדיקות הקיימות והחדשות צריכות לעבור.
- מבצעים Build ומתקינים את ההגדרות, ואז פותחים באופן ידני את הדף שרוצים לשנות. הדף אמור להתעדכן באופן מיידי.