ไลบรารีการแบ่งหน้าจะติดตามสถานะของคำขอโหลดสำหรับข้อมูลที่แบ่งหน้าและแสดงสถานะผ่านคลาส LoadState
ระบบจะให้LoadStateสัญญาณแยกกันสำหรับแต่ละLoadType และประเภทแหล่งข้อมูล (ไม่ว่าจะเป็น PagingSource หรือ RemoteMediator) ออบเจ็กต์ CombinedLoadStates ที่ Listener ระบุจะให้ข้อมูลเกี่ยวกับสถานะการโหลด จากสัญญาณทั้งหมดนี้ คุณสามารถใช้ข้อมูลโดยละเอียดนี้เพื่อแสดงตัวบ่งชี้การโหลดที่เหมาะสมต่อผู้ใช้
สถานะการโหลด
ไลบรารีการแบ่งหน้าจะแสดงสถานะการโหลดเพื่อใช้ใน UI ผ่านออบเจ็กต์
LoadState LoadState จะมีรูปแบบใดรูปแบบหนึ่งใน 3 รูปแบบต่อไปนี้ ขึ้นอยู่กับ
สถานะการโหลดปัจจุบัน
- หากไม่มีการดำเนินการโหลดที่ใช้งานอยู่และไม่มีข้อผิดพลาด
LoadStateจะเป็นออบเจ็กต์LoadState.NotLoadingคลาสย่อยนี้ยังมีพร็อพเพอร์ตี้endOfPaginationReachedซึ่งระบุว่าถึงจุดสิ้นสุดของการแบ่งหน้าแล้วหรือไม่ - หากมีการดำเนินการโหลดที่ใช้งานอยู่
LoadStateจะเป็นออบเจ็กต์LoadState.Loading - หากมีข้อผิดพลาด
LoadStateจะเป็นออบเจ็กต์LoadState.Error
เข้าถึงสถานะเหล่านี้ผ่านพร็อพเพอร์ตี้ loadState ของ Wrapper LazyPagingItems คุณใช้สถานะนี้ได้ 2 วิธี ได้แก่ การจัดการ
ระดับการมองเห็นเนื้อหาหลัก (เช่น สปินเนอร์รีเฟรชแบบเต็มหน้าจอ) หรือการแทรก
รายการที่กำลังโหลดลงในLazyColumnสตรีมโดยตรง (เช่น สปินเนอร์ส่วนท้าย)
เข้าถึงสถานะการโหลดด้วย Listener
หากต้องการตรวจสอบสถานะการโหลดใน UI ให้ใช้พร็อพเพอร์ตี้ loadState
ที่จัดทำโดย Wrapper LazyPagingItems ซึ่งจะแสดงออบเจ็กต์
CombinedLoadStatesที่ช่วยให้คุณตอบสนองต่อลักษณะการทำงานของการโหลดสำหรับเหตุการณ์
รีเฟรช เพิ่ม หรือแทรก
ในตัวอย่างต่อไปนี้ UI จะแสดงไอคอนหมุนของการโหลดหรือข้อความแสดงข้อผิดพลาด ขึ้นอยู่กับสถานะปัจจุบันของการโหลด (เริ่มต้น) ที่รีเฟรช
@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)
ซึ่งอาจทำให้ UI แสดงวงกลมโหลดชั่วครู่แม้ว่าข้อมูลที่แคชจะพร้อมใช้งานทันทีก็ตาม
หากต้องการควบคุมอย่างแม่นยำ เช่น แสดงวงกลมหมุนขณะโหลดเฉพาะเมื่อฐานข้อมูลในเครื่อง
ว่างเปล่าและเปิดใช้การซิงค์เครือข่าย ให้เข้าถึงพร็อพเพอร์ตี้ source และ mediator
โดยตรงภายใน Composable
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) } }
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับไลบรารีการแบ่งหน้าและสถานะการโหลดได้ที่แหล่งข้อมูลต่อไปนี้
เอกสารประกอบ
ดูเนื้อหา
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ภาพรวมไลบรารีการแบ่งหน้า