בהתאם למקום שאליו מעלים את המדינה (State) ולפי הלוגיקה הנדרשת, להשתמש בממשקי API שונים כדי לאחסן ולשחזר את מצב ממשק המשתמש. כל אפליקציה משתמשת שילוב של ממשקי API כדי להשיג את זה בצורה הטובה ביותר.
כל אפליקציה ל-Android עלולה לאבד את מצב ממשק המשתמש שלה בגלל פעילות או תהליך בילוי. אובדן המצב הזה יכול להתרחש בגלל האירועים הבאים:
- שינויים בהגדרות. הפעילות תושמד ותיצור מחדש אלא אם בשינוי ההגדרות האישיות מטופל באופן ידני.
- מוות של תהליך ביוזמת המערכת. האפליקציה פועלת ברקע ו המכשיר מפנה משאבים (כמו זיכרון) לשימוש על ידי תהליכים אחרים.
שימור המצב אחרי האירועים האלה הוא חיוני למשתמש חיובי חוויה אישית. בחירת המצב שיישאר תלויה במשתמש הייחודי של האפליקציה זורמים. כשיטה מומלצת, כדאי לפחות לשמור על משוב של משתמשים מצב שקשור לניווט. דוגמאות לכך כוללות את מיקום גלילה של רשימה, המזהה של הפריט שהמשתמש רוצה לקבל פרטים נוספים לגביו, התהליך בתהליך בחירה של העדפות המשתמש, או קלט בשדות הטקסט.
בדף הזה מופיע סיכום של ממשקי ה-API שזמינים לאחסון של המצב של ממשק המשתמש, בהתאם למקום שבו את המצב שלכם ואת הלוגיקה שדרושה לו.
לוגיקת ממשק המשתמש
אם המצב הועלה בממשק המשתמש, בפונקציות קומפוזביליות או בפורמט רגיל
את המחלקות של בעלי החיים בהיקף של היצירה, תוכלו להשתמש
rememberSaveable
כדי לשמור על המצב של יצירה ועיבוד של פעילויות ותהליכים.
בקטע הקוד הבא, rememberSaveable
משמש לאחסון בוליאני יחיד
מצב הרכיב בממשק המשתמש:
@Composable fun ChatBubble( message: Message ) { var showDetails by rememberSaveable { mutableStateOf(false) } ClickableText( text = AnnotatedString(message.content), onClick = { showDetails = !showDetails } ) if (showDetails) { Text(message.timestamp) } }
showDetails
הוא משתנה בוליאני שנשמר אם בועת הצ'אט מכווצת
או מורחב.
rememberSaveable
מאחסן את המצב של רכיב ממשק המשתמש ב-Bundle
באמצעות
מנגנון שמירת המצב של המכונה.
היא יכולה לאחסן סוגים בסיסיים בחבילה באופן אוטומטי. אם המדינה
נשמר בסוג שאינו פרימיטיבי, כמו מחלקת נתונים, אפשר להשתמש
מנגנוני אחסון שונים, כמו שימוש בהערה Parcelize
,
באמצעות כתיבת ממשקי API כמו listSaver
ו-mapSaver
, או הטמעה
מחלקת חיסכון בהתאמה אישית מרחיבה את המחלקה של זמן הריצה לכתיבה Saver
. לדרכים
לשמור תיעוד של המצבים כדי לקבל מידע נוסף על השיטות האלה.
בקטע הקוד הבא, לוחצים על סמל הכתיבה rememberLazyListState
ה-API מאחסן את LazyListState
, שמורכב ממצב גלילה של
LazyColumn
או LazyRow
, באמצעות rememberSaveable
. הוא משתמש
LazyListState.Saver
, שהוא שומר בהתאמה אישית שיכול
לשמור ולשחזר את מצב הגלילה. לאחר פעילות או תהליך בילוי (לגבי
לדוגמה, אחרי שינוי תצורה כמו שינוי כיוון המכשיר),
מצב הגלילה נשמר.
@Composable fun rememberLazyListState( initialFirstVisibleItemIndex: Int = 0, initialFirstVisibleItemScrollOffset: Int = 0 ): LazyListState { return rememberSaveable(saver = LazyListState.Saver) { LazyListState( initialFirstVisibleItemIndex, initialFirstVisibleItemScrollOffset ) } }
השיטה המומלצת
ב-rememberSaveable
נעשה שימוש ב-Bundle
כדי לאחסן את מצב ממשק המשתמש, שמשותף על ידי
גם ממשקי API אחרים שכותבים אליו, כמו קריאות של onSaveInstanceState()
בפעילות שלכם. עם זאת, הגודל של הBundle
הזה מוגבל, ונפח האחסון הוא גדול
אובייקטים יכולים להוביל לחריגים של TransactionTooLarge
בזמן הריצה. הזה
עלולה להיות בעייתית במיוחד באפליקציות Activity
בודדות,
נעשה שימוש ב-Bundle
בכל האפליקציה.
כדי להימנע מקריסה כזו, לא כדאי לאחסן אובייקטים מורכבים גדולים או של האובייקטים בחבילה.
במקום זאת, כדאי לאחסן את המצב המינימלי הנדרש, כמו מזהים או מפתחות, ולהשתמש בהם כדי להעניק גישה לשחזור מצב מורכב יותר של ממשק המשתמש למנגנונים אחרים, כמו מתמשך אחסון נוסף.
אפשרויות העיצוב האלה תלויות בתרחישים ספציפיים של האפליקציה ובאופן שבו היא המשתמשים מצפים ממנו להתנהג כמו שצריך.
אימות של שחזור המצב
אפשר לאמת שהמדינה ששמורה ב-rememberSaveable
בחשבון שלך
רכיבי הרכבה משוחזרים בצורה תקינה כאשר הפעילות או התהליך
מחדש. לשם כך יש ממשקי API ספציפיים, כמו
StateRestorationTester
אפשר לעיין במסמכי התיעוד בנושא בדיקה כדי
למידע נוסף.
לוגיקה עסקית
אם המצב של רכיב ממשק המשתמש הועלה אל ViewModel
כי הוא
שנדרשת על ידי הלוגיקה העסקית, אפשר להשתמש בממשקי ה-API של ViewModel
.
אחד היתרונות העיקריים של השימוש ב-ViewModel
באפליקציה ל-Android הוא
שהוא מטפל בחינם בשינויי הגדרות. כשיש מערך הגדרות אישיות
וכל הפעילות מושמדת ונוצרת מחדש, מצב ממשק המשתמש מונפק
ViewModel
נשמר בזיכרון. לאחר המשחק, ViewModel
הישן
מצורף למופע הפעילות החדש.
עם זאת, מכונה של ViewModel
לא תשרוד מוות של תהליך ביוזמת המערכת.
כדי שמצב ממשק המשתמש ישרוד זאת, השתמשו במודול המצב השמור עבור
ViewModel, שמכיל את ה-API של SavedStateHandle
.
השיטה המומלצת
SavedStateHandle
משתמש גם במנגנון Bundle
לאחסון המצב של ממשק המשתמש, כך
צריך להשתמש בו רק כדי לאחסן מצב פשוט של רכיב בממשק המשתמש.
מצב ממשק המשתמש במסך, שנוצר באמצעות החלת כללים עסקיים וגישה
בשכבות של האפליקציה מלבד ממשק המשתמש,
SavedStateHandle
עקב הגודל והמורכבות הפוטנציאליים שלו. אפשר להשתמש
מנגנונים שונים לאחסון נתונים מורכבים או גדולים, כמו שמירה על בסיס מקומי קבוע
אחסון נוסף. לאחר שחזור של תהליך, המסך נוצר מחדש עם הפונקציה
מצב זמני משוחזר שמאוחסן ב-SavedStateHandle
(אם יש כזה), וגם
המצב של ממשק המשתמש במסך נוצר שוב משכבת הנתונים.
ממשקי API של SavedStateHandle
ל-SavedStateHandle
יש ממשקי API שונים לאחסון מצב הרכיבים בממשק המשתמש, ברובם
בעיקר:
כתיבה State |
saveable() |
---|---|
StateFlow |
getStateFlow() |
כתיבת State
שימוש ב-API saveable
של SavedStateHandle
כדי לקרוא ולכתוב רכיב בממשק המשתמש
מוגדר כ-MutableState
, כך שהוא ממשיך לשרוד פעילות ועיבוד של בילוי באמצעות
עם הגדרת קוד מינימלית.
ה-API של saveable
תומך בסוגים ראשוניים מחוץ לאריזה ומקבל
stateSaver
לשימוש בערכי חיסכון בהתאמה אישית, בדיוק כמו rememberSaveable()
.
בקטע הקוד הבא, message
שומר את סוגי הקלט של המשתמשים
TextField
:
class ConversationViewModel( savedStateHandle: SavedStateHandle ) : ViewModel() { var message by savedStateHandle.saveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } private set fun update(newMessage: TextFieldValue) { message = newMessage } /*...*/ } val viewModel = ConversationViewModel(SavedStateHandle()) @Composable fun UserInput(/*...*/) { TextField( value = viewModel.message, onValueChange = { viewModel.update(it) } ) }
מידע נוסף זמין במסמכי התיעוד של SavedStateHandle
.
באמצעות ה-API של saveable
.
StateFlow
שימוש ב-getStateFlow()
כדי לאחסן את מצב הרכיב בממשק המשתמש ולצרוך אותו כתהליך
מ-SavedStateHandle
. StateFlow
נקרא
בלבד, וה-API דורש לציין מפתח כדי שתוכלו להחליף את התהליך
פולטים ערך חדש. באמצעות המפתח שהגדרת, אפשר לאחזר את StateFlow
ונאסוף את הערך העדכני ביותר.
בקטע הקוד הבא, savedFilterType
הוא משתנה StateFlow
שומר סוג מסנן שהוחל על רשימה של ערוצי צ'אט באפליקציית צ'אט:
private const val CHANNEL_FILTER_SAVED_STATE_KEY = "ChannelFilterKey" class ChannelViewModel( channelsRepository: ChannelsRepository, private val savedStateHandle: SavedStateHandle ) : ViewModel() { private val savedFilterType: StateFlow<ChannelsFilterType> = savedStateHandle.getStateFlow( key = CHANNEL_FILTER_SAVED_STATE_KEY, initialValue = ChannelsFilterType.ALL_CHANNELS ) private val filteredChannels: Flow<List<Channel>> = combine(channelsRepository.getAll(), savedFilterType) { channels, type -> filter(channels, type) }.onStart { emit(emptyList()) } fun setFiltering(requestType: ChannelsFilterType) { savedStateHandle[CHANNEL_FILTER_SAVED_STATE_KEY] = requestType } /*...*/ } enum class ChannelsFilterType { ALL_CHANNELS, RECENT_CHANNELS, ARCHIVED_CHANNELS }
בכל פעם שהמשתמש בוחר סוג מסנן חדש, מתבצעת קריאה ל-setFiltering
. הזה
שומר ערך חדש ב-SavedStateHandle
שמאוחסן באמצעות המפתח
_CHANNEL_FILTER_SAVED_STATE_KEY_
. savedFilterType
הוא זרם שפולט
הערך העדכני ביותר שמאוחסן במפתח. filteredChannels
רשום/ה לזרימה אל
מבצעים את סינון הערוצים.
במסמכי העזרה של SavedStateHandle
יש מידע נוסף על
API של getStateFlow()
.
סיכום
הטבלה הבאה מציגה סיכום של ממשקי ה-API שמפורטים בקטע הזה, ומקרים שבהם צריך להשתמש כל אחת מהן כדי לשמור את המצב של ממשק המשתמש:
אירוע | לוגיקת ממשק המשתמש | לוגיקה עסקית ב-ViewModel |
---|---|---|
שינויים בהגדרות האישיות | rememberSaveable |
אוטומטי |
מוות של תהליך ביוזמת המערכת | rememberSaveable |
SavedStateHandle |
ה-API שבו צריך להשתמש תלוי במיקום שבו המדינה (State) מוחזקת בלוגיקה
נדרש. למצב שבו נעשה שימוש בלוגיקת ממשק משתמש, משתמשים ב-rememberSaveable
. עבור
שנעשה בו שימוש בלוגיקה עסקית, אם משתמשים בו ב-ViewModel
,
שומרים אותה באמצעות SavedStateHandle
.
עליך להשתמש בממשקי ה-API של החבילה (rememberSaveable
ו-SavedStateHandle
) כדי
לאחסן כמויות קטנות של מצבי ממשק משתמש. הנתונים האלה הם המינימליים הדרושים לשחזור
את ממשק המשתמש בחזרה למצבו הקודם, ביחד עם מנגנוני אחסון אחרים. עבור
לדוגמה, אם מאחסנים את המזהה של פרופיל שהמשתמש ראה בחבילה,
אפשר לאחזר נתונים כבדים, כמו פרטי פרופיל, משכבת הנתונים.
למידע נוסף על הדרכים השונות לשמירת מצב ממשק המשתמש, אפשר לעיין שמירת תיעוד של מצב ממשק המשתמש ואת הדף שכבת נתונים של של הארכיטקטורה,
מומלץ עבורך
- הערה: טקסט הקישור מוצג כאשר JavaScript מושבת
- איפה להעלות את המצב
- State ו-Jetpack פיתוח נייטיב
- רשימות ורשתות