טיפול בשינויים בתצורה

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

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

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

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

היצירה מחדש גם מנקה את כל המצבים שנשמרו כשדות ב-Activity.

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

במאמר שמירת מצב ממשק המשתמש בפיתוח נייטיב מוסבר איך לשמור את המצב בפיתוח נייטיב.

הציפיות של המשתמשים

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

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

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

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

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

במאמר שמירת מצבי ממשק המשתמש מפורט מידע על ממשקי ה-API של כל אחת מהאפשרויות האלה, ומוסבר מתי כדאי להשתמש בכל אחת מהן.

הגבלת היצירה מחדש של פעילויות

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

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

לטיפול בשינויים בהגדרות ישירות ב-Compose יש כמה יתרונות:

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

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

<activity
    android:name=".MyActivity"
    android:recreateOnConfigChanges="keyboard|keyboardHidden|navigation|colorMode|touchscreen|...">
    ...
</activity>

תגובה לשינויים בהגדרות

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

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

שינויים בהגדרות: מושגי מפתח ושיטות מומלצות

אלה המושגים העיקריים שצריך להכיר כשעובדים על שינויים בהגדרות:

  • הגדרות אישיות: הגדרות המכשיר קובעות איך ממשק המשתמש מוצג למשתמש, למשל גודל התצוגה של האפליקציה, צפיפות המסך, הלוקאל או העיצוב של המערכת. ב-Compose, אפשר לגשת לערכי ההגדרות באמצעות LocalConfiguration.
  • שינויים בהגדרות: ההגדרות משתנות באמצעות אינטראקציה של המשתמש. לדוגמה, המשתמש יכול לשנות את הגדרות המכשיר או את האופן שבו הוא משתמש במכשיר. אי אפשר למנוע שינויים בהגדרות.
  • יצירה מחדש של Activity: שינויים בהגדרות גורמים ליצירה מחדש של 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" נמצא בקובץ המניפסט.

מקורות מידע נוספים

למידע נוסף על טיפול בשינויים בהגדרות, אפשר לעיין במקורות המידע הבאים:

תיעוד

צפייה בתוכן