一、添加依赖
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("")
}
}
}
}