我正在使用 Jetpack Compose 和 LazyPagingItems 通过 Paging 3 库在 LazyColumn 中显示分页数据。当用户返回选项卡时,我通过调用 PagingSource 上的刷新()来实现刷新功能。
但是,当我在与 LazyPagingItems 关联的 PagingSource 上调用刷新()时,整个 LazyColumn 都会刷新,导致 UI 明显重新加载并滚动回顶部。这种行为并不理想,因为它会破坏用户体验。我只需要该列更新新数据(如果有)。
我想找到一种方法来刷新 LazyPagingItems 中的数据,而不让用户注意到任何可见的更改。换句话说,我想在后台默默地更新数据。
@HiltViewModel
class MainViewModel @Inject constructor(
private val beersRepository: BeersRepository,
) : ViewModel() {
val state: Flow<PagingData<Beer>> = beersRepository
.getBeers()
.flow
.cachedIn(viewModelScope)
}
//Repository
class BeersRepository @Inject constructor(
private val beersApiService: BeersApiService,
) {
fun getBeers() = Pager(
config = PagingConfig(
pageSize = 10,
enablePlaceholders = true,
),
pagingSourceFactory = { BeersPagingSource(beersApiService = beersApiService) }
)
}
//Paging source
class BeersPagingSource @Inject constructor(
private val beersApiService: BeersApiService,
) : PagingSource<Int, Beer>() {
override fun getRefreshKey(state: PagingState<Int, Beer>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Beer> {
val page = params.key ?: 1
return try {
delay(500)
val response = beersApiService.getBeers(page, perPage = 10)
if (response.isSuccessful) {
val beers = response.body()!!.map {
it.toDomain()
}
LoadResult.Page(
data = beers,
prevKey = if (page == 1) null else page - 1,
nextKey = if (beers.isEmpty()) null else page + 1
)
} else {
LoadResult.Error(Exception(response.message()))
}
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
//And finally the Composable
private fun MainScreenRoute(
viewModel: MainViewModel = viewModel(),
) {
val pagingItems = viewModel.state.collectAsLazyPagingItems()
Scaffold(bottomBar = {
Row(
modifier = Modifier
.background(Color.Transparent)
.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
Button(onClick = {
pagingItems.refresh()
}) {
Text(
text = "Refresh", style = MaterialTheme.typography.bodyLarge
)
}
}
}) {
Surface {
Column(
modifier = Modifier.fillMaxSize()
) {
when (pagingItems.loadState.refresh) {
is LoadState.Error -> {
}
LoadState.Loading -> {
Surface {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize()
) {
Text(
text = "Loading...",
style = MaterialTheme.typography.headlineLarge
)
}
}
}
is LoadState.NotLoading -> {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(8.dp)
) {
items(pagingItems.itemCount) { index ->
val beer = pagingItems[index]!!
BeerCard(
imageUrl = beer.image,
name = beer.name,
description = beer.description,
)
}
}
}
}
}
}
}
}
已在
refresh()
上尝试 LazyPagingItems
。
您是否在 ViewModel 中缓存了
giftsList
?它应该看起来像这样:
val giftsList = repository.giftsList.cachedIn(viewModelScope)
我知道这是一个老问题,但我想分享我的解决方案。 我最终将列表放入其自己的可组合项中,然后设置它将响应哪些状态更改。 cachedIn 解决方案对我不起作用。