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

בגרסה 8.0 של Android הוספנו ארכיטקטורת מידע חדשה לאפליקציית ההגדרות כדי לפשט את אופן הארגון של ההגדרות ולאפשר למשתמשים למצוא במהירות הגדרות להתאמה אישית של מכשירי 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.

ארכיטקטורת מידע בסגנון פלאגין

כל פריט בהגדרות מיושם כ-Preference. אפשר להעביר בקלות העדפה מדף אחד לדף אחר.

כדי שיהיה קל יותר להעביר כמה הגדרות, ב-Android 8.0 הושק קטע מארח בסגנון פלאגין שמכיל את פריטי ההגדרות. פריטים של הגדרות מוגדרים כבקרים בסגנון פלאגין. לכן, דף הגדרות מורכב מקטע מארח יחיד וממספר בקרי הגדרות.

DashboardFragment

DashboardFragment הוא המארח של בקרי העדפות בסגנון פלאגין. הפלח עובר בירושה מ-PreferenceFragment ויש לו וו hooks להרחבה ולעדכון של רשימות העדפות סטטיות ודינמיות.

העדפות סטטיות

רשימת העדפות סטטית מוגדרת ב-XML באמצעות התג <Preference>. בהטמעה של DashboardFragment, משתמשים בשיטה getPreferenceScreenResId() כדי להגדיר איזה קובץ XML מכיל את רשימת ההעדפות הסטטית שרוצים להציג.

העדפות דינמיות

פריט דינמי מייצג משבצת עם כוונה, שמובילה לפעילות חיצונית או פנימית. בדרך כלל, הכוונה מובילה לדף הגדרות אחר. לדוגמה, פריט ההגדרה 'Google' בדף הבית של ההגדרות הוא פריט דינמי. פריטים דינמיים מוגדרים ב-AndroidManifest (כפי שמתואר בהמשך) ונטענים דרך FeatureProvider (המוגדרת כ- DashboardFeatureProvider).

הגדרות דינמיות הן כבדות יותר מהגדרות שהוגדרו באופן סטטי, ולכן בדרך כלל המפתחים צריכים להטמיע את ההגדרה כסטטית. עם זאת, ההגדרה הדינמית יכולה להיות שימושית אם מתקיים אחד מהמצבים הבאים:

  • ההגדרה לא מיושמת ישירות באפליקציית ההגדרות (למשל, הזרקת הגדרה שמופעלת על ידי אפליקציות של יצרן ציוד מקורי או של ספק).
  • ההגדרה אמורה להופיע בדף הבית של ההגדרות.
  • כבר יש לכם פעילות להגדרה ואתם לא רוצים להטמיע את ההגדרה הסטטית הנוספת.

כדי להגדיר פעילות כהגדרה דינמית:

  • כדי לסמן את הפעילות כהגדרה דינמית, מוסיפים לה מסנן 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 (כפי שמתואר בהמשך). לאחר מכן הן מוצגות בממשק המשתמש כרשימה מעורבת.

PreferenceController

יש הבדלים בהטמעה של PreferenceController ב-Android 9 וב-Android 8.x, כפי שמתואר בקטע הזה.

PreferenceController במהדורה של Android 9

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 לפני זמן התצוגה. במהלך ההתקנה, הבקר מחובר לקטע כך שכל האירועים הרלוונטיים העתידיים נשלחים אליו.

DashboardFragment שומרת רשימה של PreferenceController במסך. ב-onCreate() של החלק, כל הבקרים מופעלים בשיטה getAvailabilityStatus(), ואם היא מחזירה true, מתבצעת הפעלה של displayPreference() כדי לעבד את הלוגיקה של התצוגה. getAvailabilityStatus() חשוב גם להודיע למסגרת ההגדרות אילו פריטים זמינים במהלך החיפוש.

PreferenceController במהדורות של Android 8.x

PreferenceController מכיל את כל הלוגיקה ליצירת אינטראקציה עם ההעדפה, כולל הצגה, עדכון, הוספה לאינדקס החיפוש וכו'.

בהתאם לאינטראקציות של ההעדפות, לממשק של PreferenceController יש ממשקי API‏ isAvailable(), ‏ displayPreference(), ‏ handlePreferenceTreeClicked() וכו'. אפשר למצוא תיעוד מפורט על כל ממשק API בכיתה של הממשק.

במהלך התקנת ההעדפה בחלק, מרכז הבקרה מספק שיטה לצרף PreferenceController לפני זמן התצוגה. במהלך ההתקנה, הבקר מחובר לקטע כך שכל האירועים הרלוונטיים העתידיים נשלחים אליו.

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 שמכיל את ההגדרה שרוצים להעביר ומאתרים את הרשומה Activity שמייצגת את ההגדרה הזו.
  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 שמכיל את ההגדרה שרוצים להעביר ומאתרים את הרשומה Activity שמייצגת את ההגדרה הזו.
  3. משנים את ערך המטא-נתונים של הפעילות עבור com.android.settings.category, ומגדירים את נקודת הערך למפתח הקטגוריה של הדף החדש.

יצירת העדפה חדשה בדף

אם ההעדפה מופיעה באופן סטטי בקובץ ה-XML של ההעדפות של הדף המקורי, פועלים לפי התהליך הסטטי שמתואר בהמשך. אחרת, פועלים לפי התהליך הדינמי.

יצירת העדפה סטטית

  1. מאתרים את קובצי ה-XML של ההעדפות של הדף. אפשר למצוא את המידע הזה ב-method‏ getPreferenceScreenResId() של הדף.
  2. מוסיפים פריט Preference חדש ב-XML. חשוב לוודא שיש לו android:key ייחודי.
  3. מגדירים PreferenceController להעדפה הזו בשיטה getPreferenceControllers() של הדף.
    • ב-Android 8.x וב-Android 9 (אופציונלי), יוצרים מופע של PreferenceController להעדפה הזו ב-method‏ createPreferenceControllers() של הדף.

      אם ההעדפה הזו כבר הייתה קיימת במקומות אחרים, יכול להיות שכבר יש לה PreferenceController. אפשר להשתמש PreferenceController שוב בלי ליצור גרסת build חדשה.

    • החל מ-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 בהגדרות. כל הבדיקות הקיימות והחדשות אמורות לעבור.
  • יוצרים ומתקינים את ההגדרות, ואז פותחים ידנית את הדף שרוצים לשנות. הדף אמור להתעדכן באופן מיידי.