Compose - 使用 Paging

一、添加依赖

查看官方最新版本

val paging_version = "3.2.1"
implementation("androidx.paging:paging-runtime:$paging_version")
implementation("androidx.paging:paging-compose:$paging_version")

二、定义数据源 PagingSource

是对其它数据源的封装,因此和 Repository 定义在同一个 .kt 文件中并私有化。自定义一个类继承 PagingSource 并重写 load() 来提供获取页面数据。

class DemoRepository {
    fun getData() = Pager(PagingConfig(10)) {
        PagingResource()
    }.flow
}

private class PagingResource : PagingSource<Int, HotNewestArticleBean.HotNewestArticle.Article>() {
    private val startPage = 0
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, HotNewestArticleBean.HotNewestArticle.Article> {
        return try {
            val currentPage = params.key ?: startPage
            val data = getData(currentPage)
            val prevKey = if (currentPage > startPage) currentPage - 1 else null
            val nextKey = if (data.isNotEmpty()) currentPage + 1 else null
            LoadResult.Page(data, prevKey, nextKey)
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }

    override fun getRefreshKey(state: PagingState<Int, HotNewestArticleBean.HotNewestArticle.Article>): Int? {
        return null
    }

    //具体获取数据的方法。这里能更细分的对异常处理,否则在load()中合并返回后在UI中难区分。
    //但处理后还是要抛出异常,不然load()不会返回异常,影响UI中对Paging状态判断
    private suspend fun getData(currentPage: Int): List<HotNewestArticleBean.HotNewestArticle.Article> {
        var data: List<HotNewestArticleBean.HotNewestArticle.Article> = emptyList()
        runCatching {
            withContext(Dispatchers.IO) {
                RetrofitClient.apiService.newestArticle(currentPage.toString())
            }
        }.onSuccess { response ->
            response.getData().onSuccess {
                data = it.datas
            }.onFailure {
                Log.e("服务器错误", it.message.toString())
                throw Exception("服务器错误:${it.message}")
            }
        }.onFailure {
            Log.e("本地错误", it.message.toString())
            throw Exception("本地错误:${it.message}")
        }
        return data
    }
}

三、ViewModel 中调用

class DemoViewModel : ViewModel() {
    private val repository = DemoRepository()
    var pagingDataFlow = repository.getData().cachedIn(viewModelScope)    //缓存在ViewModel中
}

四、UI

collectAsLazyPagingItems()方法将Flow<PagingData<T>>转换为一个LazyPagingItems<T>对象。这个对象可以被LazyColumn或者LazyRow等Jetpack Compose中的列表组件使用,来动态地加载和显示数据。

@Composable
fun DemoScreen(
    viewModel: DemoViewModel = viewModel()
) {
    //将Paging的数据从Flow转为可供LazyColumn使用的
    val lazyPagingItems = viewModel.pagingDataFlow.collectAsLazyPagingItems()
    //监听Paging状态
    when (lazyPagingItems.loadState.refresh) {
        //正在加载
        is LoadState.Loading -> {}
        //加载错误(这里的错误是PagingSource里捕获的)
        is LoadState.Error -> {}
        //当没有加载动作并且没有错误的时候
        is LoadState.NotLoading -> {}
    }
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        state = lazyListState
    ){
        items(
            count = lazyPagingItems.itemCount,
            key = lazyPagingItems.itemKey { it.id }
        ) { index ->
            val bean = lazyPagingItems[index]
            if (bean != null) {
                val author = bean.author
                val shareUser = bean.shareUser
                val superChapterName = bean.superChapterName
                Item(
                    title = bean.title,
                    author = if (author.isEmpty()) String.format("%s · %s", superChapterName, shareUser) else String.format("%s · %s", superChapterName, author),
                    time = bean.niceDate,
                )
            } else {
                Text("")
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值