पेजिंग लाइब्रेरी, पेज किए गए डेटा के लिए लोड अनुरोधों की स्थिति को ट्रैक करती है. साथ ही, इसे LoadState क्लास के ज़रिए दिखाती है.
हर LoadType और डेटा सोर्स टाइप (PagingSource या RemoteMediator) के लिए, एक अलग LoadState सिग्नल दिया जाता है. लिसनर से मिला CombinedLoadStates ऑब्जेक्ट, इन सभी सिग्नल से लोड होने की स्थिति के बारे में जानकारी देता है. इस जानकारी का इस्तेमाल करके, उपयोगकर्ताओं को लोड होने के सही इंडिकेटर दिखाए जा सकते हैं.
राज्यों की जानकारी लोड हो रही है
पेजिंग लाइब्रेरी, LoadState ऑब्जेक्ट की मदद से यूज़र इंटरफ़ेस (यूआई) में इस्तेमाल करने के लिए, लोड होने की स्थिति दिखाती है. LoadState ऑब्जेक्ट, लोड होने की मौजूदा स्थिति के आधार पर, इन तीन में से किसी एक फ़ॉर्मैट में होते हैं:
- अगर कोई लोड ऑपरेशन चालू नहीं है और कोई गड़बड़ी नहीं है, तो
LoadStateएकLoadState.NotLoadingऑब्जेक्ट है. इस सबक्लास मेंendOfPaginationReachedप्रॉपर्टी भी शामिल है. इससे पता चलता है कि पेज नंबरिंग खत्म हो गई है या नहीं. - अगर कोई लोड ऑपरेशन चालू है, तो
LoadStateएकLoadState.Loadingऑब्जेक्ट है. - अगर कोई गड़बड़ी होती है, तो
LoadStateएकLoadState.Errorऑब्जेक्ट है.
इन स्थितियों को अपने LazyPagingItems रैपर की loadState प्रॉपर्टी की मदद से ऐक्सेस करें. इस स्टेट का इस्तेमाल दो तरीकों से किया जा सकता है: मुख्य कॉन्टेंट की विज़िबिलिटी को मैनेज करना (जैसे, फ़ुल-स्क्रीन रीफ़्रेश स्पिनर) या लोड हो रहे आइटम को सीधे LazyColumn स्ट्रीम में शामिल करना (जैसे, फ़ुटर स्पिनर).
लिसनर की मदद से, लोड होने की स्थिति को ऐक्सेस करना
अपने यूज़र इंटरफ़ेस (यूआई) में लोडिंग की स्थिति पर नज़र रखने के लिए, LazyPagingItems रैपर से मिली loadState प्रॉपर्टी का इस्तेमाल करें. यह एक CombinedLoadStates ऑब्जेक्ट दिखाता है. इसकी मदद से, रीफ़्रेश करने, अपेंड करने या प्रीपेंड करने वाले इवेंट के लिए, लोड होने के व्यवहार पर प्रतिक्रिया दी जा सकती है.
यहां दिए गए उदाहरण में, यूज़र इंटरफ़ेस (यूआई) में लोडिंग स्पिनर या गड़बड़ी का मैसेज दिखता है. यह मैसेज, रीफ़्रेश (शुरुआती) लोड की मौजूदा स्थिति के आधार पर दिखता है:
@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 ऑब्जेक्ट का इस्तेमाल करके, हेडर के लिए प्रीपेंड स्टेट और फ़ुटर के लिए अपेंड स्टेट को मॉनिटर किया जा सकता है.
यहां दिए गए उदाहरण में, ज़्यादा डेटा फ़ेच किए जाने पर, सूची के सबसे नीचे प्रोग्रेस बार या 'फिर से कोशिश करें' बटन दिखता है:
@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() } }
pagingItems.loadState, स्क्रोल करने के दौरान prepend या append में बदलाव होने पर, हर बार एक नया CombinedLoadStates ऑब्जेक्ट दिखाता है. इसलिए, रीफ़्रेश की जांच को remember(pagingItems) के साथ derivedStateOf में रैप करें. इससे स्क्रोल-एज अपडेट, पैरंट स्कोप को फिर से कंपोज़ नहीं कर पाते. यह स्कोप, सिर्फ़ फ़ुल-स्क्रीन रीफ़्रेश इंडिकेटर को टॉगल करता है:
val showFullScreenLoading by remember(pagingItems) { derivedStateOf { // Avoid recomposing on prepend or append updates while scrolling, and // avoid covering existing items during a background refresh. pagingItems.loadState.source.refresh is LoadState.Loading && pagingItems.itemCount == 0 } } if (showFullScreenLoading) { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { CircularProgressIndicator() } }
लोड होने की स्थिति में बदलावों पर प्रतिक्रिया देना
लोड होने की स्थिति में बदलावों के आधार पर, आपको एक बार होने वाले खराब असर को ट्रिगर करना पड़ सकता है. जैसे, सूची में सबसे ऊपर स्क्रोल करना या रीफ़्रेश होने या न होने पर Snackbar दिखाना.
स्टेटस में होने वाले बदलावों को स्ट्रीम के तौर पर देखने के लिए, LaunchedEffect के अंदर snapshotFlow का इस्तेमाल करें. इससे आपको खास इवेंट को अलग करने के लिए, filter, distinctUntilChanged, और distinctUntilChangedBy जैसे स्टैंडर्ड Flow ऑपरेटर लागू करने की सुविधा मिलती है.
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) } }
इसी तरह, loadState पर distinctUntilChangedBy का इस्तेमाल करके, गड़बड़ी का मैसेज Snackbar सिर्फ़ तब दिखाया जा सकता है, जब refresh की स्थिति LoadState.Error में बदल जाए:
val snackbarHostState = remember { SnackbarHostState() } // Key on pagingItems rather than loadState so state updates do not restart the // coroutine and reset distinctUntilChangedBy. LaunchedEffect(pagingItems) { snapshotFlow { pagingItems.loadState } // Ignore prepend and append updates so scrolling does not re-trigger the // refresh error Snackbar. .distinctUntilChangedBy { it.refresh } .filter { it.refresh is LoadState.Error } .collect { loadState -> val error = (loadState.refresh as LoadState.Error).error val result = snackbarHostState.showSnackbar( message = "Data failed to load: ${error.localizedMessage ?: "Unknown error"}", actionLabel = "Retry" ) if (result == SnackbarResult.ActionPerformed) { pagingItems.retry() } } }
अन्य संसाधन
पेजिंग लाइब्रेरी और लोड होने की स्थितियों के बारे में ज़्यादा जानने के लिए, यहां दिए गए लेख पढ़ें.
दस्तावेज़
कॉन्टेंट देखना
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर, लिंक टेक्स्ट दिखता है
- पेजिंग लाइब्रेरी के बारे में खास जानकारी