Paging 3 列表在 Jetpack Compose 导航返回导航时自动刷新
Paging 3 list auto refresh on navigation back in jetpack compose navigation
我正在使用 Jetpack Compose,以及 Paging 3 库和 Jetpack Navigation。我面临的问题是我有一个 LazyList,它使用分页库从远程源获取数据。
ViewModel
fun getImages(): Flow<PagingData<ObjectImage>> = Pager(
PagingConfig(PAGE_SIZE, enablePlaceholders = false)
) { DataHome(RANDOM) }.flow.cachedIn(viewModelScope)
主页视图
val images = viewModelHome.getImages().collectAsLazyPagingItems()
LazyColumn {
...
}
现在发生的事情是当我使用 navHostController.navigate()
导航到另一个视图,然后按返回键返回主视图... LazyColumn 会自行重置并再次开始从网络加载项目。
所以我被这个问题困住了。我尝试在 viewModel 变量中手动缓存...虽然它有效但它搞砸了 SwipeRefresh(停止显示刷新状态)
data.apply {
when {
// refresh
loadState.refresh is LoadState.Loading -> {
ItemLoading()
}
// reload
loadState.append is LoadState.Loading -> {...}
// refresh error
loadState.refresh is LoadState.Error -> {...}
// reload error
loadState.append is LoadState.Error -> {...}
}
}
implementation("androidx.paging:paging-runtime-ktx:3.1.0")
implementation("androidx.paging:paging-compose:1.0.0-alpha14")
这是仍处于 alpha 阶段的 PagingLibrary 的问题吗??
Update 1 (I am not sure if this is a good solution, but I am solving
the swipe refresh issue as follows)
// get images
var images: Flow<PagingData<ObjectImage>> = Pager(PagingConfig(PAGE_SIZE)) {
DataHome(RANDOM)
}.flow.cachedIn(viewModelScope)
// reload items
fun reload(){
images = Pager(PagingConfig(PAGE_SIZE)) {
DataHome(RANDOM)
}.flow.cachedIn(viewModelScope)
}
// and rather than calling .refresh() method on lazy items... I am calling viewModel.reload()
问题是您每次调用 getImages()
时都会创建新的 Pager
,也就是每次您的可组合项重新组合时,这不是应该的方式。
您应该将其设置为 val items = Pager(...
以便缓存工作。
对于搞砸的SwipeRefresh
,你是如何实现的? LazyPagingItems
上有一个 refresh() 方法,你应该使用它。
编辑:好的,根据对您问题的评论和编辑:
在您的视图模型中,按照我之前的建议进行操作:
val items = Pager( // define your pager here
您的可组合项可以如下所示:
@Composable
fun Screen() {
val items = viewModel.items.collectAsLazyPagingItems()
val state = rememberSwipeRefreshState(
isRefreshing = items.loadState.refresh is LoadState.Loading,
)
SwipeRefresh(
modifier = Modifier.fillMaxSize(),
state = state,
// use the provided LazyPagingItems.refresh() method,
// no need for custom solutions
onRefresh = { items.refresh() }
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
) {
// display the items only when loadState.refresh is not loading,
// as you wish
if (items.loadState.refresh is LoadState.NotLoading) {
items(items) {
if (it != null) {
Text(
modifier = Modifier.padding(16.dp),
text = it,
)
}
}
// you can also add item for LoadState.Error, anything you want
if (items.loadState.append is LoadState.Loading) {
item {
Box(modifier = Modifier.fillMaxWidth()) {
CircularProgressIndicator(
modifier = Modifier
.align(Alignment.Center)
.padding(16.dp)
)
}
}
}
}
// if the loadState.refresh is Loading,
// display just single loading item,
// or nothing at all (SwipeRefresh already indicates
// refresh is in progress)
else if (items.loadState.refresh is LoadState.Loading) {
item {
Box(modifier = Modifier.fillParentMaxSize()) {
Text(
text = "Refreshing",
modifier = Modifier.align(Alignment.Center))
}
}
}
}
}
}
我正在使用 Jetpack Compose,以及 Paging 3 库和 Jetpack Navigation。我面临的问题是我有一个 LazyList,它使用分页库从远程源获取数据。
ViewModel
fun getImages(): Flow<PagingData<ObjectImage>> = Pager(
PagingConfig(PAGE_SIZE, enablePlaceholders = false)
) { DataHome(RANDOM) }.flow.cachedIn(viewModelScope)
主页视图
val images = viewModelHome.getImages().collectAsLazyPagingItems()
LazyColumn {
...
}
现在发生的事情是当我使用 navHostController.navigate()
导航到另一个视图,然后按返回键返回主视图... LazyColumn 会自行重置并再次开始从网络加载项目。
所以我被这个问题困住了。我尝试在 viewModel 变量中手动缓存...虽然它有效但它搞砸了 SwipeRefresh(停止显示刷新状态)
data.apply {
when {
// refresh
loadState.refresh is LoadState.Loading -> {
ItemLoading()
}
// reload
loadState.append is LoadState.Loading -> {...}
// refresh error
loadState.refresh is LoadState.Error -> {...}
// reload error
loadState.append is LoadState.Error -> {...}
}
}
implementation("androidx.paging:paging-runtime-ktx:3.1.0")
implementation("androidx.paging:paging-compose:1.0.0-alpha14")
这是仍处于 alpha 阶段的 PagingLibrary 的问题吗??
Update 1 (I am not sure if this is a good solution, but I am solving the swipe refresh issue as follows)
// get images
var images: Flow<PagingData<ObjectImage>> = Pager(PagingConfig(PAGE_SIZE)) {
DataHome(RANDOM)
}.flow.cachedIn(viewModelScope)
// reload items
fun reload(){
images = Pager(PagingConfig(PAGE_SIZE)) {
DataHome(RANDOM)
}.flow.cachedIn(viewModelScope)
}
// and rather than calling .refresh() method on lazy items... I am calling viewModel.reload()
问题是您每次调用 getImages()
时都会创建新的 Pager
,也就是每次您的可组合项重新组合时,这不是应该的方式。
您应该将其设置为 val items = Pager(...
以便缓存工作。
对于搞砸的SwipeRefresh
,你是如何实现的? LazyPagingItems
上有一个 refresh() 方法,你应该使用它。
编辑:好的,根据对您问题的评论和编辑:
在您的视图模型中,按照我之前的建议进行操作:
val items = Pager( // define your pager here
您的可组合项可以如下所示:
@Composable
fun Screen() {
val items = viewModel.items.collectAsLazyPagingItems()
val state = rememberSwipeRefreshState(
isRefreshing = items.loadState.refresh is LoadState.Loading,
)
SwipeRefresh(
modifier = Modifier.fillMaxSize(),
state = state,
// use the provided LazyPagingItems.refresh() method,
// no need for custom solutions
onRefresh = { items.refresh() }
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
) {
// display the items only when loadState.refresh is not loading,
// as you wish
if (items.loadState.refresh is LoadState.NotLoading) {
items(items) {
if (it != null) {
Text(
modifier = Modifier.padding(16.dp),
text = it,
)
}
}
// you can also add item for LoadState.Error, anything you want
if (items.loadState.append is LoadState.Loading) {
item {
Box(modifier = Modifier.fillMaxWidth()) {
CircularProgressIndicator(
modifier = Modifier
.align(Alignment.Center)
.padding(16.dp)
)
}
}
}
}
// if the loadState.refresh is Loading,
// display just single loading item,
// or nothing at all (SwipeRefresh already indicates
// refresh is in progress)
else if (items.loadState.refresh is LoadState.Loading) {
item {
Box(modifier = Modifier.fillParentMaxSize()) {
Text(
text = "Refreshing",
modifier = Modifier.align(Alignment.Center))
}
}
}
}
}
}