ארכיטקטורת מידע

ב-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 ולהעביר את הקוד ל-controller לפני שיוצרים מופע שלו ב-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>

בזמן רינדור, רכיב ה-Fragment יבקש רשימה של העדפות מ-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

  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. מוסיפים פריט Preference חדש ב-XML. מוודאים שיש לו android:key ייחודי.
  3. מגדירים PreferenceController להעדפה הזו בשיטת getPreferenceControllers() של הדף.
    • ב-Android מגרסה 8.x ובאופן אופציונלי ב-Android מגרסה 9, יוצרים מופע של PreferenceController להעדפה הזו ב-method‏ 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 בהגדרות. כל הבדיקות הקיימות והחדשות צריכות לעבור.
  • מבצעים Build ומתקינים את ההגדרות, ואז פותחים באופן ידני את הדף שרוצים לשנות. הדף אמור להתעדכן באופן מיידי.