יצירת ווידג'ט בסיסי

איך עושים את זה ב-Compose
‫Jetpack Compose היא ערכת הכלים המומלצת לפיתוח ממשק משתמש ב-Android. איך יוצרים ווידג'טים באמצעות ממשקי API בסגנון Compose.

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

דוגמה לווידג'ט מוזיקה
איור 1. דוגמה לווידג'ט מוזיקה.

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

במאמר סקירה כללית על ווידג'טים של אפליקציות מוסבר איך לעצב את הווידג'ט.

רכיבי הווידג'ט

כדי ליצור ווידג'ט, צריך את הרכיבים הבסיסיים הבאים:

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

באיור 2 אפשר לראות איך הרכיבים האלה משתלבים בתהליך העיבוד הכולל של הווידג'ט של האפליקציה.

תהליך העיבוד של ווידג'ט האפליקציה
איור 2. תהליך העיבוד של הווידג'ט של האפליקציה.

אם הווידג'ט דורש הגדרות של המשתמש, צריך להטמיע את פעילות הגדרת הווידג'ט של האפליקציה. הפעילות הזו מאפשרת למשתמשים לשנות את הגדרות הווידג'ט, למשל את אזור הזמן של ווידג'ט השעון.

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

הצהרה על קובץ ה-XML של AppWidgetProviderInfo

הגדרת המטא-נתונים (כמו גודל ברירת המחדל של התאים, מגבלות על שינוי הגודל ותדירות העדכון) זהה לחלוטין בתצוגות המסורתיות ובווידג'טים שמבוססים על Glance.

כדי ללמוד איך להגדיר את קובץ ה-XML של המטא-נתונים, עיינו בקטע הצהרה על קובץ ה-XML של AppWidgetProviderInfo ב-Compose-first במסמכי התיעוד של Glance.

שימוש במחלקה AppWidgetProvider כדי לטפל בשידורי ווידג'טים

מנגנוני מקלט השידור של הפלטפורמה, מסנני הצהרת המניפסט ולולאות האירועים של מחזור החיים מאוחדים מתחת לפלטפורמה. בפיתוח שמתמקד ב-Compose, השידורים האלה מנוהלים באמצעות ה-wrapper של GlanceAppWidgetReceiver.

כדי להבין איך לרשום את המקלט במניפסט ולהטמיע שינויים תואמי-Hilt במחזור החיים, עיינו בקטע שימוש במחלקה AppWidgetProvider לטיפול בשידורים בתיעוד של Glance.

יצירת פריסת הווידג'ט

צריך להגדיר פריסה ראשונית לווידג'ט ב-XML ולשמור אותה בספרייה res/layout/ של הפרויקט. פרטים נוספים זמינים בהנחיות לעיצוב.

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

‫RemoteViews תומך גם ב-ViewStub, שהוא View בלתי נראה בגודל אפס, שבו אפשר להשתמש כדי להרחיב משאבי פריסה באופן עצל בזמן הריצה.

תמיכה בהתנהגות עם שמירת מצב (stateful)

ב-Android 12 נוספה תמיכה בהתנהגות עם שמירת מצב באמצעות הרכיבים הקיימים הבאים:

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

דוגמה לווידג'ט של רשימת קניות שמציג התנהגות עם שמירת מצב (stateful)
איור 3. דוגמה להתנהגות עם שמירת מצב.

בדוגמת הקוד הבאה אפשר לראות איך מטמיעים את הרכיבים האלה.

// Check the view.
remoteView.setCompoundButtonChecked(R.id.my_checkbox, true)

// Check a radio group.
remoteView.setRadioGroupChecked(R.id.my_radio_group, R.id.radio_button_2)

// Listen for check changes. The intent has an extra with the key
// EXTRA_CHECKED that specifies the current checked state of the view.
remoteView.setOnCheckedChangeResponse(
    R.id.my_checkbox,
    RemoteViews.RemoteResponse.fromPendingIntent(onCheckedChangePendingIntent)
)

צריך לספק שני פריסות: אחת שמטרגטת מכשירים עם Android מגרסה 12 ואילך ב-res/layout-v31, והשנייה שמטרגטת מכשירים עם Android מגרסה 11 ומטה בתיקיית ברירת המחדל res/layout.

הטמעת פינות מעוגלות

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

כדי להטמיע פינות מעוגלות או להגדיר סגנונות דינמיים במכשירי Android ישנים יותר, עיינו בקטע הטמעת פינות מעוגלות ב-Compose-first במסמכי התיעוד של Glance.

שמירה על תמונות RemoteViews במסגרת מגבלות הזיכרון של המערכת

ווידג'טים פועלים בתוך התהליך של מרכז האפליקציות במסך הבית, ו-system_server אוכפת מגבלת זיכרון של מפת סיביות (bitmap) לכל ווידג'ט (6 * width * height בייטים; מידע נוסף זמין במאמר בנושא שינוי ההתנהגות של מגבלת הזיכרון של ווידג'טים ב-Android 17). כשיוצרים ווידג'טים קלאסיים של AppWidgetProvider באמצעות RemoteViews, צריך לבצע את הפעולות הבאות:

  • ‫Downsample bitmaps using WindowMetrics: ברמת API‏ 30 ומעלה, מחשבים את תקציב מפת הסיביות המקסימלי מ-WindowManager.currentWindowMetrics.bounds במקום מ-resources.displayMetrics, ומפענחים תמונות אטומות באמצעות Bitmap.Config.RGB_565 ו-inSampleSize בחזקת שתיים.
  • כשמחליפים תמונות, משתמשים בקריאות מלאות של updateAppWidget: אל תפעילו את partiallyUpdateAppWidget כדי לעדכן מפות סיביות של ImageView או מזהי URI של Icon, כי עדכונים חלקיים מוסיפים פעולות להיררכיה של RemoteViews שנשמרה במטמון ב-system_server בלי לשחרר הקצאות קודמות של תמונות.
  • הוספת עבודה ברקע לתור באמצעות WorkManager: אל תפעילו את Context.startForegroundService מ-AppWidgetProvider.onReceive או מ-onUpdate, כי הפעולה הזו גורמת להצגת השגיאה ForegroundServiceStartNotAllowedException כשהיא מופעלת ברקע. במקום זאת, צריך להוסיף לתור WorkManager CoroutineWorker, ולהעביר את context.applicationContext כשמנפחים או מעדכנים את RemoteViews מ-background workers.