I set up navigation, pagination and use flow to connect ui with model. If simplify, my screen code looks like this:
@Composable
MainScreen() {
val listState = rememberLazyListState()
val lazyItems = Pager(PagingConfig(...)) { ... }
.flow
.cachedIn(viewModelScope)
.collectAsLazyPagingItems()
LazyColumn(state = listState) {
items(lazyItems, key = { it.id }) { ... }
}
}
And here is my NavHost code:
NavHost(navController, startDestination = "mainScreen") {
composable("mainScreen") {
MainScreen()
}
}
But when i navigate back to MainScreen from another screen or just opening the drawer, data is loaded from DataSource again and i see noticeable blink of LazyColumn
.
How to avoid reloading data?
Your code gives me the following error for cachedIn
:
Flow operator functions should not be invoked within composition
You shouldn't ignore such warnings.
During transition Compose Navigation recomposes both disappearing and appearing views many times. This is the expected behavior.
And your code creates a new Pager
with a new flow on each recomposition, which is causing the problem.
The easiest way to solve it is using remember
: it'll cache the pager flow between recompositions:
val lazyItems = remember {
Pager(PagingConfig(/* ... */)) { /* ... */ }
.flow
.cachedIn(viewModelScope)
.collectAsLazyPagingItems()
}
But it'll still be reset during configuration change, e.g. device rotation. The best way to prevent this is moving this logic into a view model:
class MainScreenViewModel : ViewModel() {
val pagingFlow = Pager(PagingConfig(/* ... */)) { /* ... */ }
.flow
.cachedIn(viewModelScope)
}
@Composable
fun MainScreen(
viewModel = viewModel<MainScreenViewModel>()
) {
val lazyItems = viewModel.pagingFlow.collectAsLazyPagingItems()
}