חלק מההגדרות של המכשיר יכולות להשתנות בזמן שהאפליקציה פועלת. ההגדרות האלה כוללות, בין היתר:
- גודל התצוגה של האפליקציה
- כיוון המסך
- גודל ועובי הגופן
- לוקאל
- מצב כהה לעומת מצב בהיר
- זמינות המקלדת
רוב השינויים האלה בתצורה מתרחשים בעקבות אינטראקציה כלשהי של המשתמש. לדוגמה, סיבוב או קיפול של המכשיר משנים את כמות שטח המסך שזמינה לאפליקציה. באופן דומה, שינוי של הגדרות המכשיר כמו גודל הגופן, השפה או העיצוב המועדף משנה את הערכים שלהם באובייקט Configuration.
הפרמטרים האלה בדרך כלל דורשים שינויים גדולים מספיק בממשק המשתמש של האפליקציה, ולכן לפלטפורמת Android יש מנגנון ייעודי לשינויים כאלה.
המנגנון הזה נקרא Activityיצירה מחדש.
יצירת פעילות
המערכת יוצרת מחדש Activity כשמתבצע שינוי בהגדרות. לשם כך, המערכת קוראת ל-onDestroy ומשמידה את המופע הקיים של Activity. לאחר מכן נוצרת מכונה חדשה באמצעות onCreate, והמכונה החדשה הזו של Activity מאותחלת עם ההגדרה החדשה והמעודכנת. המשמעות היא שהמערכת יוצרת מחדש את ממשק המשתמש עם ההגדרה החדשה.
בדרך כלל, Activity משמש כמארח של פונקציות Composable. כשמערכת Compose יוצרת מחדש את Activity, היא גם יוצרת מחדש את ממשק המשתמש באמצעות ערכי ההגדרה החדשים.
ההתנהגות של יצירה מחדש עוזרת לאפליקציה להסתגל להגדרות חדשות על ידי טעינה מחדש אוטומטית של האפליקציה עם משאבים חלופיים שתואמים להגדרת המכשיר החדשה.
דוגמה לשימוש בנתוני בילוי
נניח שיש קומפוזבילי שמציג כותרת סטטית באמצעות משאב מחרוזת:
// In the res/values/strings.xml file // <string name="compose">Jetpack Compose</string> // In your Compose code Text( text = stringResource(R.string.compose) )
כשיוצרים את הרכיב Activity, הרכיב הקומפוזבילי Text קורא את ההגדרה הנוכחית (למשל, השפה) ומחזיר את משאב המחרוזת המתאים.
אם השפה משתנה, המערכת יוצרת מחדש את הפעילות. במקרה כזה, ממשק המשתמש של כלי הכתיבה נוצר מחדש. מכיוון שהתג stringResource קורא מההגדרה הנוכחית, שם הפריט מתעדכן אוטומטית לערך המקומי הנכון.
בנוסף, השחזור מנקה את כל המצב שנשמר כשדות ב-Activity.
כדי לשמר את מצב ממשק המשתמש אחרי שינויים בהגדרות, צריך להשתמש בדפוסי ניהול מצב מומלצים. משתמשים ב-ViewModel לנתונים וללוגיקה עסקית, וב-rememberSaveable למצב ברמת ממשק המשתמש. באמצעות המנגנונים האלה, המצב נשמר אחרי יצירה מחדש של Activity, בזמן שממשק המשתמש מתעדכן כדי לשקף את ההגדרה החדשה.
מידע נוסף על שמירת מצב ב-Compose זמין במאמר שמירת מצב ממשק המשתמש ב-Compose.
הציפיות של המשתמשים
המשתמשים מצפים שהמצב של האפליקציה יישמר. אם משתמש ממלא טופס ופותח אפליקציה אחרת במצב מרובה חלונות כדי לעיין במידע, חוויית המשתמש תהיה גרועה אם הוא יחזור לטופס ריק או למקום אחר באפליקציה. כמפתחים, אתם צריכים לספק חוויית משתמש עקבית באמצעות שינויים בהגדרות ויצירה מחדש של פעילות.
כדי לוודא שהמצב נשמר באפליקציה, אפשר לבצע פעולות שגורמות לשינויים בהגדרות בזמן שהאפליקציה פועלת בחזית ובזמן שהיא פועלת ברקע. פעולות אלה כוללות:
- סיבוב המכשיר
- כניסה למצב ריבוי חלונות
- שינוי הגודל של האפליקציה במצב ריבוי חלונות או בחלון חופשי
- קיפול של מכשיר מתקפל עם כמה מסכים
- שינוי העיצוב של המערכת, כמו מצב כהה לעומת מצב בהיר
- שינוי גודל הגופן
- שינוי השפה של המערכת או של האפליקציה
- חיבור או ניתוק של מקלדת פיזית
- חיבור או ניתוק של תחנת עגינה
יש כמה גישות שבהן אפשר להשתמש כדי לשמור את המצב הרלוונטי במהלך יצירה מחדש של Activity. הגישה שבה תשתמשו תלויה בסוג המצב שאתם רוצים לשמור:
- שמירת נתונים במאגר מקומי כדי לטפל בסיום התהליך של נתונים מורכבים או גדולים.
שמירת נתונים במאגר מקומי כוללת מסדי נתונים או
DataStore. - אובייקטים שנשמרים כמו מופעים של
ViewModelלטיפול במצב שקשור לממשק המשתמש בזיכרון בזמן שהמשתמש משתמש באפליקציה באופן פעיל. -
rememberSaveableכדי לשמור על מצב ממשק המשתמש הזמני במהלך שינויים בהגדרות והשבתת תהליכים שהמערכת יזמה. זה מתאים למצב שתלוי בקלט של משתמשים, במיקום הגלילה או בניווט, אבל לא שייך ל-ViewModel.
במאמר שמירת מצבי ממשק המשתמש מוסבר בפירוט על כל אחד מממשקי ה-API האלה ומתי כדאי להשתמש בכל אחד מהם.
הגבלת יצירה מחדש של פעילות
אפשר למנוע יצירה מחדש אוטומטית של פעילות עבור שינויים מסוימים בהגדרות. באפליקציות מודרניות שמבוססות על Compose בלבד, ממשק המשתמש מורכב מחדש בכל מקרה, אבל מומלץ לטפל בשינוי ההגדרה ישירות.
כברירת מחדל, שינוי בהגדרות גורם למערכת להרוס וליצור מחדש את הפעילות, כולל ממשק המשתמש וכל האובייקטים שנגזרים מהפעילות. אם מצהירים שהפעילות מטפלת בשינוי ההגדרות בעצמה, המערכת מונעת את זה. במקום זאת, רק האובייקט Configuration מתעדכן, ו-Compose מרכיב מחדש את ממשק המשתמש עם הערכים החדשים.
יש כמה יתרונות לטיפול בשינויים בהגדרות ישירות ב-Compose:
- ביצועים משופרים: הרכבה מחדש של ממשק המשתמש היא פחות יקרה ממחזור מלא של יצירת פעילות מחדש, במיוחד כשמדובר בשינויים קלים.
- אנימציות חלקות: הימנעות מהפעלה מחדש של Activity מאפשרת להפעיל אנימציות רציפות במהלך שינויים בהגדרות, כמו מעברים חלקים בפריסה במהלך סיבוב המכשיר.
- שמירת מצב: שמירת מופע הפעילות מצמצמת את הסיכון לאובדן זמני של מצב ממשק המשתמש במהלך אירוע כמו סיבוב המסך. שימו לב שעדיין צריך לטפל בשמירת המצב במקרה של סיום תהליך שהמערכת יזמה.
כדי להשבית את היצירה מחדש של פעילות עבור שינויים מסוימים בהגדרות, מוסיפים את סוג ההגדרה ל-android:configChanges ברשומה <activity> בקובץ AndroidManifest.xml. הערכים האפשריים מפורטים במסמכי התיעוד של מאפיין android:configChanges.
קוד המניפסט הבא משבית את היצירה מחדש של Activity עבור MyActivity כשמשנים את כיוון המסך ואת הזמינות של המקלדת:
<activity
android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="@string/app_name">
תגובה לשינויים בהגדרות
Jetpack Compose מאפשר לאפליקציה להגיב בקלות רבה יותר לשינויים בהגדרות. עם זאת, אם משביתים את Activityהיצירה מחדש לכל השינויים בהגדרות שאפשר להשבית, האפליקציה עדיין צריכה לטפל בצורה נכונה בשינויים בהגדרות.
האובייקט Configuration זמין בהיררכיית ממשק המשתמש של Compose עם הלוקאל של הקומפוזיציה LocalConfiguration. בכל פעם שהערך משתנה, פונקציות LocalConfiguration.current שקוראות ממנו מורכבות מחדש. מידע על אופן הפעולה של משתנים מקומיים של קומפוזיציה זמין במאמר נתונים בהיקף מקומי עם CompositionLocal.
דוגמה
בדוגמה הבאה, רכיב שאפשר להרכיב ממנו ממשק משתמש מציג תאריך בפורמט ספציפי.
הרכיב הקומפוזבילי מגיב לשינויים בהגדרות הלוקאל של המערכת על ידי קריאה ל-ConfigurationCompat.getLocales עם LocalConfiguration.current.
@Composable
fun DateText(year: Int, dayOfYear: Int) {
val dateTimeFormatter = DateTimeFormatter.ofPattern(
"MMM dd",
ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
)
Text(
dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
)
}
כדי למנוע יצירה מחדש של Activity כשמשנים את הלוקאל, צריך להגדיר את Activity שמארח את קוד ה-Compose כך שלא יחולו עליו שינויים בהגדרת הלוקאל. כדי לעשות את זה, צריך להגדיר את android:configChanges ל-locale|layoutDirection.
שינויים בהגדרות: מושגים מרכזיים ושיטות מומלצות
אלה המושגים העיקריים שחשוב להכיר כשעובדים על שינויים בהגדרות:
- הגדרות: הגדרות המכשיר קובעות איך ממשק המשתמש מוצג למשתמש, למשל גודל התצוגה של האפליקציה, המקום או העיצוב של המערכת. במצב כתיבה, אפשר לגשת לערכי ההגדרה באמצעות
LocalConfiguration. - שינויים בהגדרות: ההגדרות משתנות באמצעות אינטראקציה של המשתמש. לדוגמה, המשתמש יכול לשנות את הגדרות המכשיר או את האופן שבו הוא מתקשר פיזית עם המכשיר. אין דרך למנוע שינויים בהגדרות.
- יצירה מחדש של
Activity: שינויים בהגדרות גורמים ליצירה מחדש שלActivityכברירת מחדל. זהו מנגנון מובנה לאתחול מחדש של מצב האפליקציה עבור ההגדרה החדשה. Activityהשמדה:Activityיצירה מחדש גורמת למערכת להשמיד את המופע הישן שלActivityוליצור מופע חדש במקומו. המופע הישן מיושן. מומלץ להימנע משמירת הפניות לאובייקטים עם היקף מחזור חיים מעבר להיקף המיועד שלהם.- מצב: המצב במופע הישן של
Activityלא קיים במופע החדש, כי אלה שני מופעים שונים של אובייקטים.Activityבמקום לקשר את המצב לפעילות, צריך להשתמש בממשקי API מומלצים כדי לשמור את מצב האפליקציה והמשתמש, כמו שמתואר במאמר שמירת מצבי ממשק המשתמש. - ביטול הסכמה: כדי לבטל את ההסכמה ליצירה מחדש של פעילות עבור סוג של שינוי בהגדרות, צריך לוודא שהאפליקציה מתעדכנת בצורה תקינה בתגובה להגדרה החדשה.
כדי לספק חוויית משתמש טובה, מומלץ לפעול לפי השיטות המומלצות הבאות:
- התכוננו לשינויים תכופים בהגדרות: אל תניחו ששינויים בהגדרות הם נדירים או לא קורים אף פעם, ללא קשר לרמת ה-API, לגורם הצורה או לערכת הכלים של ממשק המשתמש. כשמשתמש גורם לשינוי בהגדרות, הוא מצפה שהאפליקציות יתעדכנו וימשיכו לפעול בצורה תקינה עם ההגדרה החדשה.
- שמירת מצב: לא לאבד את מצב המשתמש כשמתרחש יצירה מחדש של
Activity. שומרים את המצב כמו שמתואר במאמר שמירת מצבי ממשק המשתמש באמצעות ממשקי API כמוViewModelו-rememberSaveable. - אל תשתמשו בהשבתה כפתרון מהיר: אל תשביתו את יצירת
Activityמחדש כקיצור דרך כדי למנוע אובדן של מצב. השבתה של יצירת פעילות מחדש מחייבת אתכם לקיים את ההבטחה לטפל בשינוי, ועדיין יכול להיות שתאבדו את המצב בגלל יצירה מחדש שלActivityמשינויים אחרים בהגדרות, מסיום התהליך או מסגירת האפליקציה. אי אפשר להשבית לחלוטין את יצירתActivityמחדש. צריך לשמור את המצב כמו שמתואר במאמר שמירת מצבי ממשק המשתמש. - לא להימנע משינויים בהגדרות: לא להגביל את הכיוון, יחס הגובה-רוחב או שינוי הגודל כדי להימנע משינויים בהגדרות ומשינוי הגדרות
Activity. הדבר פוגע במשתמשים שרוצים להשתמש באפליקציה שלכם בדרך המועדפת עליהם.
טיפול בשינויים בהגדרות על סמך גודל
שינויים בהגדרות על סמך גודל יכולים לקרות בכל שלב, והם סבירים יותר כשהאפליקציה פועלת במכשיר עם מסך גדול שבו המשתמשים יכולים להיכנס למצב מרובה חלונות. הם מצפים שהאפליקציה תפעל בצורה טובה בסביבה הזו.
יש שני סוגים כלליים של שינויים בגודל: משמעותיים ולא משמעותיים. שינוי גודל משמעותי הוא שינוי שבו חל על ההגדרה החדשה סט שונה של משאבים חלופיים, בגלל הבדל בגודל המסך, כמו רוחב, גובה או הרוחב הקטן ביותר. המשאבים האלה כוללים את המשאבים שהאפליקציה מגדירה בעצמה ואת המשאבים מכל אחת מהספריות שלה.
הגבלת יצירה מחדש של פעילות לשינויים בהגדרות שמבוססים על גודל
כשמשביתים את היצירה מחדש של Activity לשינויים בהגדרות שמבוססים על גודל, המערכת לא יוצרת מחדש את Activity. במקום זאת, היא מקבלת קריאה ל-Activity.onConfigurationChanged. כל רכיב קומפוזבילי שקורא את LocalConfiguration.current עובר קומפוזיציה מחדש באופן אוטומטי כדי לשקף את הגודל החדש.
היצירה מחדש של Activity מושבתת לשינויים בהגדרות לפי גודל כשמוסיפים את android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" לקובץ המניפסט.
מקורות מידע נוספים
למידע נוסף על טיפול בשינויים בהגדרות, אפשר לעיין במקורות המידע הנוספים הבאים: