חלק מהגדרות המכשיר יכולות להשתנות בזמן שהאפליקציה פועלת. הדוגמאות כוללות, בין היתר:
- גודל התצוגה של האפליקציה
- כיוון המסך
- גודל ועובי הגופן
- לוקאל
- מצב כהה לעומת מצב בהיר
- זמינות המקלדת
רוב השינויים האלה בתצורה מתרחשים בעקבות אינטראקציה כלשהי של המשתמש. לדוגמה, סיבוב או קיפול של המכשיר משנים את כמות שטח המסך שזמינה לאפליקציה. באופן דומה, שינוי של הגדרות המכשיר כמו גודל הגופן, השפה או העיצוב המועדף משנה את הערכים שלהם באובייקט Configuration.
הפרמטרים האלה בדרך כלל דורשים שינויים גדולים מספיק בממשק המשתמש של האפליקציה, ולכן לפלטפורמת Android יש מנגנון ייעודי לשינויים כאלה.
המנגנון הזה נקרא Activityיצירה מחדש.
יצירת פעילות
המערכת יוצרת מחדש Activity כשמתבצע שינוי בהגדרות. כדי לעשות את זה, המערכת קוראת ל-onDestroy ומשמידה את מופע Activity הקיים. לאחר מכן נוצרת מכונה חדשה באמצעות onCreate, והמכונה החדשה הזו מסוג Activity מאותחלת עם ההגדרה החדשה והמעודכנת. המשמעות היא שהמערכת יוצרת מחדש את ממשק המשתמש עם ההגדרה החדשה.
בדרך כלל, Activity משמש כמאחסן של רכיבים שאפשר להרכיב. כשיוצרים מחדש את Activity, Compose יוצר מחדש גם את ממשק המשתמש באמצעות ערכי ההגדרה החדשים.
ההתנהגות של יצירה מחדש עוזרת לאפליקציה להסתגל להגדרות חדשות על ידי טעינה מחדש אוטומטית של האפליקציה עם משאבים חלופיים שתואמים להגדרת המכשיר החדשה.
דוגמה לשימוש בנתוני בילוי
נניח שיש קומפוזבילי שמציג כותרת סטטית באמצעות משאב מחרוזת:
// 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">
Android 17
החל מ-Android 17 (רמת API 37), המערכת לא מפעילה מחדש פעילויות כברירת מחדל עבור כמה שינויים בהגדרות, שבדרך כלל לא דורשים יצירה מחדש מלאה של ממשק המשתמש.
במקום זאת, הפעילויות נשארות פעילות ומקבלות עדכונים באמצעות הקריאה החוזרת onConfigurationChanged().
השינויים הספציפיים בהגדרות כוללים:
CONFIG_KEYBOARDCONFIG_KEYBOARD_HIDDENCONFIG_NAVIGATIONCONFIG_TOUCHSCREENCONFIG_COLOR_MODE-
CONFIG_UI_MODE(רק כשמצב ממשק המשתמש משתנה לUI_MODE_TYPE_DESKאו מUI_MODE_TYPE_DESKלסוג אחר)
אם האפליקציה שלכם מסתמכת על הפעלה מחדש מלאה כדי לטעון מחדש משאבים עבור השינויים האלה, עכשיו אתם צריכים להביע הסכמה מפורשת להתנהגות הישנה באמצעות המאפיין android:recreateOnConfigChanges בקובץ המניפסט.
המאפיין מאפשר לציין אילו שינויים בהגדרות צריכים להפעיל מחזור של עצירה, השמדה ויצירה מחדש של פעילות מלאה, למשל:
<activity
android:name=".MyActivity"
android:recreateOnConfigChanges="keyboard|keyboardHidden|navigation|colorMode|touchscreen|...">
...
</activity>
תגובה לשינויים בהגדרות
עם 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. כל רכיבי ה-Composable שקוראים את LocalConfiguration.current יורכבו מחדש באופן אוטומטי כדי לשקף את הגודל החדש.
היצירה מחדש של Activity מושבתת לשינויים בהגדרות שמבוססים על גודל, אם יש לכם android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" בקובץ המניפסט.
מקורות מידע נוספים
למידע נוסף על טיפול בשינויים בהגדרות, אפשר לעיין במקורות המידע הנוספים הבאים: