Дважды обновляется экран приложения на Compose. Что не так?
Есть классическое приложение с двумя экранами - на первом список, на втором подробности. Для списка используется пагинация Paging 3. (для меня это новое) Проблема в том, что при переходе на второй экран и возвращении назад экран со списком обновляется дважды. Очевидно, проблема где-то в том что дважды вызывается обновление данных, но я в упор не вижу где. Если сделать загрузку просто 100 элементов из списка, то никаких проблем. Помогите, пожалуйста, увидеть ошибку.
override fun onCreate(savedInstanceState: Bundle?) {
component.inject(this)
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = POKEMONS_LIST_SCREEN
) {
composable(POKEMONS_LIST_SCREEN) {
val data = pokemonsListViewModel.getPokemonList().collectAsLazyPagingItems()
PokemonListScreen(
data = data,
pokemonsListViewModel = pokemonsListViewModel) {
navController.navigate("$POKEMONS_DETAILS_SCREEN/$it")
}
}
composable("$POKEMONS_DETAILS_SCREEN/{name}") { name ->
val pokemonName = name.arguments?.getString("name")
PokemonDetailsScreen(
pokemonDetailsViewModel = pokemonDetailsViewModel,
name = pokemonName
)
}
}
}
}
@Composable
fun PokemonListScreen(
data: LazyPagingItems<PokemonListResult>,
pokemonsListViewModel: PokemonsListViewModel,
onClickNav: (String) -> Unit
) {
Log.d("Qaz", "qaz")
Scaffold(){innerPadding ->
Box(modifier = Modifier.padding(innerPadding)){
when (data.loadState.refresh) {
is LoadState.Error -> {}
LoadState.Loading -> {}
is LoadState.NotLoading -> {
LazyColumn {
items(data) { item ->
Card(Modifier.clickable {
if (item != null) {
onClickNav(item.name)
}
}) {
if (item != null) {
Text(text = "${item.name}")
}
}
}
}
}
}
}
}
}
class PokemonsListViewModel @Inject constructor(
private val pokemonList: GetPokemonList
) : ViewModel() {
fun getPokemonList() = pokemonList.getPokemonList()
}
class PokemonPagingSource(
private val loader: PokemonApi
) : PagingSource<Int, PokemonListResult>() {
override fun getRefreshKey(state: PagingState<Int, PokemonListResult>): Int? {
return state.anchorPosition
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, PokemonListResult> {
val key = params.key ?: 0
val offset = params.loadSize * key
return try {
val response = loader.getPokemonList(limit = params.loadSize, offset = offset)
val pokelist = response.pokelist
val nextKey = if (pokelist.size < params.loadSize) null else key + 1
LoadResult.Page(
data = pokelist,
prevKey = null,
nextKey = nextKey
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
class PokemonRepositoryImpl @Inject constructor(
private val api: PokemonApi
) : PokemonRepository {
override fun getPokemonList(): Flow<PagingData<PokemonListResult>> {
return Pager(
config = PagingConfig(pageSize = PAGE_SIZE, initialLoadSize = PAGE_SIZE),
pagingSourceFactory = { PokemonPagingSource(loader = api) }
).flow
}
override suspend fun getPokemonDetails(name: String): PokemonDetails {
return api.getPokemonDetailsByName(name)
}
companion object {
const val PAGE_SIZE = 20
}
}
Ответы (1 шт):
Автор решения: EtCetera
→ Ссылка
А всё просто оказалось - ответ кроется здесь:
class PokemonsListViewModel @Inject constructor(
private val pokemonList: GetPokemonList
) : ViewModel() {
fun getPokemonList() = pokemonList.getPokemonList()
}
Если сделать вот так:
val state = pokemonList.getPokemonList().cachedIn(viewModelScope)
то всё работает.