Di chuyển sang Paging 3

Paging 3 có sự khác biệt đáng kể so với các phiên bản thư viện Paging trước đó. Phiên bản này cung cấp chức năng nâng cao, khả năng hỗ trợ hàng đầu cho các coroutine Kotlin và Flow, cũng như khả năng tích hợp liền mạch với Jetpack Compose.

Những lợi ích của việc chuyển sang Paging 3

Paging 3 bao gồm những tính năng mà các phiên bản thư viện trước đó chưa có:

  • Khả năng hỗ trợ hàng đầu cho các coroutine và Flow Kotlin.
  • Trạng thái tải tích hợp và các tín hiệu lỗi cho thiết kế giao diện người dùng thích ứng, bao gồm chức năng thử lại và làm mới.
  • Những cải tiến đối với lớp kho lưu trữ, bao gồm khả năng hỗ trợ hành động huỷ và giao diện nguồn dữ liệu được đơn giản hoá.
  • Những cải tiến đối với tầng trình diễn, dấu phân cách danh sách, biến đổi trang tuỳ chỉnh, tiêu đề và chân trang, cũng như các mục trạng thái tải cho danh sách tải từng phần.

Di chuyển ứng dụng sang Paging 3

Để di chuyển hoàn toàn sang Paging 3, bạn phải di chuyển những thành phần chính này từ Paging 2:

  • Các lớp DataSource
  • PagedList
  • Lớp trình bày (đến LazyPagingItems)

Tuy nhiên, một số thành phần Paging 3 có khả năng tương thích ngược với các phiên bản Paging trước. Cụ thể, API Pager có thể sử dụng các đối tượng DataSource cũ bằng phương thức asPagingSourceFactory. Điều này có nghĩa là bạn có các lựa chọn di chuyển sau:

  • Bạn có thể di chuyển DataSource sang PagingSource nhưng không thay đổi phần còn lại của quá trình triển khai Paging.
  • Bạn có thể di chuyển toàn bộ quá trình triển khai Paging để di chuyển hoàn toàn ứng dụng sang Paging 3.

Các phần trên trang này giải thích cách di chuyển các thành phần Paging trên mỗi lớp của ứng dụng.

Các lớp DataSource

Phần này mô tả tất cả các thay đổi cần thiết để di chuyển quá trình triển khai Paging cũ để sử dụng PagingSource.

PageKeyedDataSource, PositionalDataSourceItemKeyedDataSource từ Paging 2 đều được kết hợp vào API PagingSource trong Paging 3. Các phương thức tải từ tất cả các lớp API cũ được kết hợp thành một phương thức load duy nhất trong PagingSource. Điều này giảm việc trùng lặp mã vì đa số logic của các phương thức tải trong quá trình triển khai các lớp API cũ giống nhau.

Trong Paging 3, tất cả các thông số phương thức tải được thay thế bằng một lớp kín LoadParams, bao gồm các lớp con cho mỗi loại tải. Nếu bạn cần phân biệt các loại tải trong phương thức load, hãy kiểm tra lớp con nào của LoadParams sau đây đã được truyền: LoadParams.Refresh,LoadParams.Prepend hoặc LoadParams.Append.

Để tìm hiểu thêm về cách triển khai PagingSource, hãy xem bài viết Xác định nguồn dữ liệu.

Làm mới khoá

Các cách triển khai PagingSource phải xác định cách thức làm mới tiếp tục từ giữa dữ liệu tải đã phân trang. Thực hiện việc này bằng cách triển khai getRefreshKey để ánh xạ khoá khởi động chính xác bằng cách sử dụng state.anchorPosition làm chỉ mục được truy cập gần đây nhất.

// Replaces ItemKeyedDataSource.
override fun getRefreshKey(state: PagingState<String, User>): String? {
  return state.anchorPosition?.let { anchorPosition ->
    state.getClosestItemToPosition(anchorPosition)?.id
  }
}

// Replacing PositionalDataSource.
override fun getRefreshKey(state: PagingState<Int, User>): Int? {
  return state.anchorPosition
}

Biến đổi các danh sách

Trong các phiên bản thấp hơn của thư viện Paging, việc chuyển đổi dữ liệu được phân trang sẽ dựa trên các phương thức sau:

  • DataSource.map
  • DataSource.mapByPage
  • DataSource.Factory.map
  • DataSource.Factory.mapByPage

Trong Paging 3, tất cả các phép biến đổi được áp dụng làm toán tử trên PagingData. Nếu bạn sử dụng bất kỳ phương thức nào trong danh sách trước đó để biến đổi danh sách được phân trang, bạn phải chuyển logic biến đổi của mình từ DataSource vào PagingData khi tạo Pager bằng PagingSource.

Để tìm hiểu thêm về cách biến đổi dữ liệu được phân trang bằng Paging 3, hãy xem bài viết Biến đổi các luồng dữ liệu.

PagedList

Phần này mô tả tất cả các thay đổi cần thiết để di chuyển quá trình triển khai Paging cũ để sử dụng PagerPagingData trong Paging 3.

Các lớp PagedListBuilder

PagingData thay thế PagedList hiện có khỏi Phân trang 2. Để di chuyển sang PagingData, bạn phải cập nhật các thông tin sau:

  • Cấu hình Paging được di chuyển từ PagedList.Config sang PagingConfig.
  • Các lớp trình tạo cũ đã được kết hợp thành một lớp Pager duy nhất.
  • Pager hiển thị Flow<PagingData> có thể quan sát bằng thuộc tính .flow.
val flow = Pager(
  // Configure how data is loaded by passing additional properties to
  // PagingConfig, such as prefetchDistance.
  PagingConfig(pageSize = 20)
) {
  ExamplePagingSource(backend, query)
}.flow
  .cachedIn(viewModelScope)

Để tìm hiểu thêm về cách thiết lập một luồng phản hồi gồm các đối tượng PagingData bằng Paging 3, hãy xem bài viết Thiết lập luồng PagingData.

BoundaryCallback cho các nguồn được phân lớp

Trong Paging 3, RemoteMediator sẽ thay thế PagedList.BoundaryCallback làm trình xử lý để phân trang dữ liệu từ mạng và cơ sở dữ liệu.

Để tìm hiểu thêm về cách sử dụng RemoteMediator để phân trang dữ liệu từ mạng và cơ sở dữ liệu trong Paging 3, hãy xem Lớp học lập trình Android Paging.

LazyPagingItems

Phần này mô tả tất cả các thay đổi cần thiết để di chuyển quá trình triển khai Paging cũ để sử dụng LazyPagingItems trong Paging 3.

Paging 3 cung cấp collectAsLazyPagingItems để xử lý luồng PagingData mới. Để di chuyển lớp trình bày, hãy dùng cấu phần phần mềm paging-composecollectAsLazyPagingItems để thu thập các mục PagingData rồi hiển thị chúng trong các hàm @Composable.

Để tìm hiểu thêm về LazyPagingItems, hãy xem bài viết Tải và hiển thị dữ liệu được phân trang.

So sánh và cập nhật danh sách

Nếu bạn hiện đang sử dụng logic so sánh danh sách tuỳ chỉnh, hãy di chuyển phương thức triển khai của bạn để sử dụng LazyPagingItems được cung cấp trong Paging 3. Để đảm bảo quá trình so sánh diễn ra đúng cách, hãy chỉ định một khoá mục trên danh sách tải từng phần:

@Composable
fun UserScreen(viewModel: UserViewModel) {
    // Collects the Flow into a LazyPagingItems object
    val lazyPagingItems = viewModel.pager.flow.collectAsLazyPagingItems()

    UserList(lazyPagingItems)
}

@Composable
fun UserScreen(viewModel: UserViewModel) {
    val lazyPagingItems = viewModel.pager.flow.collectAsLazyPagingItems()

    UserList(lazyPagingItems)
}

@Composable
fun UserList(lazyPagingItems: LazyPagingItems<User>) {
    LazyColumn {
        items(
            count = lazyPagingItems.itemCount,
            // Provide a stable key for each item, similar to DiffUtil in Views
            key = lazyPagingItems.itemKey { user -> user.id } 
        ) { index ->
            val user = lazyPagingItems[index]
            if (user != null) {
                UserRow(user = user)
            }
        }
    }
}

Để biết thêm thông tin về khoá mục, hãy xem phần Khoá mục.

Các trạng thái đang tải

Trong Phân trang 3, bạn không cần một bộ điều hợp riêng để hiển thị tiêu đề hoặc chân trang cho trạng thái tải. Đối tượng LazyPagingItems hiển thị một thuộc tính loadState mà bạn có thể kiểm tra trực tiếp trong LazyColumn.

LazyColumn {
    // ... items(lazyPagingItems) go here ...

    // Show loading spinner at bottom of list when appending data
    if (lazyPagingItems.loadState.append is LoadState.Loading) {
        item {
            CircularProgressIndicator(modifier = Modifier.fillMaxWidth())
        }
    }
}

Tài nguyên khác

Để tìm hiểu thêm về thư viện Paging, hãy xem các tài nguyên khác sau đây:

Tài liệu

Xem nội dung