ספריית Paging עוקבת אחרי הסטטוס של בקשות טעינה של נתונים עם חלוקה לדפים, ומציגה אותו באמצעות המחלקה LoadState.
אות LoadState נפרד מסופק לכל LoadType ולכל סוג של מקור נתונים (PagingSource או RemoteMediator). האובייקט CombinedLoadStates שמסופק על ידי ה-listener מספק מידע על מצב הטעינה מכל האותות האלה. אתם יכולים להשתמש במידע המפורט הזה כדי להציג למשתמשים את אינדיקטורי הטעינה המתאימים.
מצבי טעינה
ספריית Paging חושפת את מצב הטעינה לשימוש בממשק המשתמש באמצעות האובייקט LoadState. אובייקטים מסוג LoadState יכולים להופיע באחת משלוש צורות, בהתאם למצב הטעינה הנוכחי:
- אם אין פעולת טעינה פעילה ואין שגיאה, אז
LoadStateהוא אובייקטLoadState.NotLoading. מחלקת המשנה הזו כוללת גם את המאפייןendOfPaginationReached, שמציין אם הגעתם לסוף של חלוקת הדפים. - אם יש פעולת טעינה פעילה, אז
LoadStateהוא אובייקטLoadState.Loading. - אם יש שגיאה, אז
LoadStateהוא אובייקטLoadState.Error.
אפשר לגשת למדינות האלה דרך המאפיין loadState של רכיב העטיפה LazyPagingItems. אפשר להשתמש במצב הזה בשתי דרכים: לטפל בנראות של התוכן הראשי (למשל, סמל טעינה של רענון במסך מלא) או להוסיף פריטי טעינה ישירות לזרם LazyColumn (למשל, סמל טעינה בכותרת התחתונה).
גישה למצב הטעינה באמצעות מאזין
כדי לעקוב אחר מצב הטעינה בממשק המשתמש, משתמשים בנכס loadState שמוגדר על ידי wrapper LazyPagingItems. הפונקציה מחזירה אובייקט CombinedLoadStates שמאפשר להגיב להתנהגות הטעינה של אירועים מסוג refresh, append או prepend.
בדוגמה הבאה, בממשק המשתמש מוצג סימן גרפי שפעולה מתבצעת או הודעת שגיאה, בהתאם למצב הנוכחי של הטעינה (ההתחלתית):
@Composable fun UserListScreen(viewModel: UserViewModel) { val pagingItems = viewModel.flow.collectAsLazyPagingItems() Box(modifier = Modifier.fillMaxSize()) { // Show the list content LazyColumn { items(pagingItems.itemCount) { index -> UserItem(pagingItems[index]) } } // Handle the loading state when (val state = pagingItems.loadState.refresh) { is LoadState.Loading -> { CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) } is LoadState.Error -> { ErrorButton( message = state.error.message ?: "Unknown error", onClick = { pagingItems.retry() }, modifier = Modifier.align(Alignment.Center) ) } else -> {} // No separate view needed for success/not loading } } }
מידע נוסף על LazyPagingItems זמין במאמר קבוצות גדולות של נתונים (חלוקה לדפים).
הוספת כותרות עליונות ותחתונות לטעינה
כדי להציג אינדיקטורים של טעינה בתחילת הרשימה או בסופה (ככותרות עליונות או כותרות תחתונות), מוסיפים בלוקים ייעודיים של פריטים במיוחד למצבים האלה בהיקף של LazyColumn.
אפשר לעקוב אחרי מצב ההוספה של הכותרת ומצב הצירוף של הכותרת התחתונה באמצעות האובייקט CombinedLoadStates.
בדוגמה הבאה, כשמאחזרים עוד נתונים, מוצג פס התקדמות או לחצן ניסיון חוזר בתחתית הרשימה:
פריטי מצב הטעינה יוצגו בסוף רכיבי ה-placeholder.@Composable fun UserList(viewModel: UserViewModel) { val pagingItems = viewModel.pager.flow.collectAsLazyPagingItems() LazyColumn { // 1. Header (Prepend state) // Useful if you support bidirectional paging or jumping to the middle item { val prependState = pagingItems.loadState.prepend if (prependState is LoadState.Loading) { LoadingItem() } else if (prependState is LoadState.Error) { ErrorItem( message = prependState.error.message ?: "Error", onClick = { pagingItems.retry() } ) } } // 2. Main Data items(pagingItems.itemCount) { index -> UserItem(pagingItems[index]) } // 3. Footer (Append state) // Shows when the user scrolls to the bottom and more data is loading item { val appendState = pagingItems.loadState.append if (appendState is LoadState.Loading) { LoadingItem() } else if (appendState is LoadState.Error) { ErrorItem( message = appendState.error.message ?: "Error", onClick = { pagingItems.retry() } ) } } } } @Composable fun LoadingItem() { Box(modifier = Modifier.fillMaxWidth().padding(16.dp), contentAlignment = Alignment.Center) { CircularProgressIndicator() } } @Composable fun ErrorItem(message: String, onClick: () -> Unit) { Column( modifier = Modifier.fillMaxWidth().padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text(text = message, color = Color.Red) Button(onClick = onClick) { Text("Retry") } } }
גישה למידע נוסף על מצב הטעינה
כפי שרואים בדוגמאות הקודמות, קל להתקשר אל pagingItems.loadState.refresh. עם זאת, הוא מסתיר את ההבדל בין טעינה ממסד הנתונים המקומי (PagingSource) לבין טעינה מהרשת (RemoteMediator).
הדבר עלול לגרום להצגת סמל טעינה בממשק המשתמש למשך זמן קצר, גם כשנתונים במטמון זמינים באופן מיידי.
כדי לשלוט בצורה מדויקת, למשל להציג אנימציה של טעינה רק כשהמסד הנתונים המקומי ריק ומתבצע סנכרון עם הרשת, אפשר לגשת ישירות למאפיינים source ו-mediator בתוך הקומפוזיציה.
val loadState = pagingItems.loadState val isSyncing = loadState.mediator?.refresh is LoadState.Loading val isLocalEmpty = loadState.source.refresh is LoadState.NotLoading && pagingItems.itemSnapshotList.items.isEmpty() if (isSyncing && isLocalEmpty) { FullScreenLoading() } else { UserList(pagingItems) if (isSyncing) { TopOverlaySpinner() } }
תגובה לשינויים במצב הטעינה
יכול להיות שתצטרכו להפעיל תופעות לוואי חד-פעמיות על סמך שינויים במצב הטעינה, כמו גלילה לראש הרשימה או הצגת Snackbar כשטעינה מחדש מסתיימת.
אפשר להשתמש ב-snapshotFlow בתוך LaunchedEffect כדי לראות את השינויים במצב כזרם. כך אפשר להחיל אופרטורים סטנדרטיים של Flow כמו filter
ו-distinctUntilChanged כדי לבודד אירועים ספציפיים.
val listState = rememberLazyListState() LaunchedEffect(pagingItems) { // 1. Convert the state to a Flow snapshotFlow { pagingItems.loadState.refresh } // 2. Filter for the specific event (Refresh completed successfully) .distinctUntilChanged() .filter { it is LoadState.NotLoading } .collect { // 3. Trigger the side effect listState.animateScrollToItem(0) } }
מקורות מידע נוספים
מידע נוסף על ספריית Paging ומצבי טעינה זמין במקורות המידע הבאים.
תיעוד
צפייה בתוכן
מומלץ בשבילכם
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- סקירה כללית של ספריית Paging