חלק מהגדרות המכשיר יכולות להשתנות בזמן שהאפליקציה פועלת. הדרישות האלה כוללות, בין היתר:
- גודל התצוגה של האפליקציה
- כיוון המסך
- גודל ועובי הגופן
- לוקאל
- מצב כהה לעומת מצב בהיר
- זמינות המקלדת
רוב השינויים האלה בתצורה מתרחשים בעקבות אינטראקציה כלשהי של המשתמש. לדוגמה, סיבוב או קיפול של המכשיר משנים את כמות שטח המסך שזמינה לאפליקציה. באופן דומה, שינוי של הגדרות המכשיר כמו גודל הגופן, השפה או העיצוב המועדף משנה את הערכים שלהם באובייקט Configuration.
הפרמטרים האלה בדרך כלל דורשים שינויים גדולים מספיק בממשק המשתמש של האפליקציה, ולכן לפלטפורמת Android יש מנגנון ייעודי לשינויים כאלה.
המנגנון הזה נקרא יצירה מחדש של Activity.
יצירת פעילות
המערכת יוצרת מחדש את Activity כשמתרחש שינוי בהגדרות. לשם כך, המערכת קוראת ל-onDestroy ומשמידה את מופע Activity הקיים. לאחר מכן המערכת יוצרת מכונה חדשה באמצעות onCreate, ומכונת Activity החדשה הזו מאותחלת עם ההגדרה החדשה והמעודכנת. המשמעות היא שהמערכת יוצרת מחדש את ממשק המשתמש עם ההגדרה החדשה.
בדרך כלל, הרכיב Activity משמש כמאחסן של רכיבים שאפשר להרכיב. כשיוצרים מחדש את Activity, גם ממשק המשתמש נוצר מחדש באמצעות ערכי ההגדרה החדשים.
ההתנהגות של יצירה מחדש עוזרת לאפליקציה להסתגל להגדרות חדשות על ידי טעינה מחדש אוטומטית של האפליקציה עם משאבים חלופיים שתואמים להגדרת המכשיר החדשה.
דוגמה לשימוש ב-Recreation
נניח שיש קומפוזבילי שמציג כותרת סטטית באמצעות משאב מחרוזת:
// 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 פיתוח נייטיב, האפליקציה יכולה להגיב בקלות רבה יותר לשינויים בהגדרות.
עם זאת, אם משביתים את היצירה מחדש של Activity לכל שינוי בהגדרות שאפשר להשבית, האפליקציה עדיין צריכה לטפל בשינויים בהגדרות בצורה נכונה.
אובייקט Configuration זמין בהיררכיית ממשק המשתמש של Compose עם LocalConfiguration composition local. בכל פעם שמשתנה, פונקציות הניתנות להגדרה שקוראות מ-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 מומלצים כדי לשמור את מצב האפליקציה והמשתמש, כמו שמתואר במאמר שמירת מצבי ממשק המשתמש. - ביטול הסכמה: כדי לבטל את ההסכמה ליצירה מחדש של פעילות עבור סוג של שינוי בהגדרות, צריך לוודא שהאפליקציה מתעדכנת בצורה תקינה בתגובה להגדרה החדשה. ברוב אפליקציות Compose, לא מומלץ להשתמש באפשרות הזו.
כדי לספק חוויית משתמש טובה, מומלץ לפעול לפי השיטות המומלצות הבאות:
- התכוננו לשינויים תכופים בהגדרות: אל תניחו ששינויים בהגדרות הם נדירים או לא קורים בכלל, בלי קשר לרמת ה-API, לגורם הצורה או לערכת הכלים של ממשק המשתמש. כשמשתמש גורם לשינוי בהגדרות, הוא מצפה שהאפליקציות יתעדכנו וימשיכו לפעול בצורה תקינה עם ההגדרות החדשות.
- שמירת מצב: לא לאבד את מצב המשתמש כשמתבצעת יצירה מחדש של
Activity. שומרים את המצב כמו שמתואר במאמר שמירת מצבי ממשק המשתמש באמצעות ממשקי API כמוViewModelו-rememberSaveable. - לא כדאי להשתמש בהשבתה כפתרון מהיר: אל תשביתו את השחזור של
Activityכקיצור דרך כדי למנוע אובדן של מצב. גם אם משביתים את יצירת הפעילות מחדש, עדיין יכול להיות שהמצב ייעלם בגלל יצירה מחדש שלActivityמשינויים אחרים בהגדרות, השבתת תהליך או סגירת האפליקציה. אי אפשר להשבית לגמרי את יצירתActivityמחדש. שומרים את המצב כמו שמתואר במאמר שמירת מצבי ממשק המשתמש. - לא להימנע משינויים בהגדרות: לא להגביל את הכיוון, יחס הגובה-רוחב או שינוי הגודל כדי להימנע משינויים בהגדרות ומשינוי הגודל של
Activity. הדבר פוגע במשתמשים שרוצים להשתמש באפליקציה בדרך המועדפת עליהם.
טיפול בשינויים בהגדרות על סמך גודל
שינויים בהגדרות על סמך גודל יכולים לקרות בכל שלב, והם סבירים יותר אם האפליקציה פועלת במכשיר עם מסך גדול שבו המשתמשים יכולים להיכנס למצב מרובה חלונות. הם מצפים שהאפליקציה תפעל היטב בסביבה הזו.
יש שני סוגים כלליים של שינויים בגודל: משמעותיים ולא משמעותיים. שינוי גודל משמעותי הוא שינוי שבו חל על ההגדרה החדשה סט שונה של משאבים חלופיים בגלל הבדל בגודל המסך, כמו רוחב, גובה או הרוחב הקטן ביותר. המקורות האלה כוללים את אלה שהאפליקציה מגדירה בעצמה ואת אלה מכל אחת מהספריות שלה.
הגבלת יצירה מחדש של פעילות לשינויים בהגדרות שמבוססים על גודל
כשמשביתים את Activity היצירה מחדש לשינויים בהגדרות לפי גודל, המערכת לא יוצרת מחדש את Activity. במקום זאת, הוא מקבל שיחה למספר Activity.onConfigurationChanged. כל רכיבי ה-Composable שקוראים את LocalConfiguration.current יורכבו מחדש באופן אוטומטי כדי לשקף את הגודל החדש.
יצירה מחדש של Activity מושבתת לשינויים בהגדרות לפי גודל כשמוסיפים את android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" לקובץ המניפסט.
מקורות מידע נוספים
למידע נוסף על טיפול בשינויים בהגדרות, אפשר לעיין במקורות המידע הנוספים הבאים: