lelestacia
lelestacia

Reputation: 519

paging3 state always stuck at the end of first page when navigating away

So, i was learning jetpack compose, and trying to make an anime index app which use paging3, pagingcompose,and lazy layout. But, even when i save the lazy state in rememberlazyliststate and rememberlazygridstate, the paging state is always stuck at the end of page 1, i also tried to restore state on compose navigation but still it didn't work as i expected.

Here is my code for flow and ui state on viewmodel:

 private val anime: Flow<PagingData<Anime>> = displayedAnimeType.flatMapLatest { type ->
    when (type) {
        DisplayType.POPULAR -> useCases.getPopularAnime().cachedIn(viewModelScope)
        DisplayType.AIRING -> useCases.getAiringAnime().cachedIn(viewModelScope)
        DisplayType.UPCOMING -> useCases.getUpcomingAnime().cachedIn(viewModelScope)
        DisplayType.SEARCH -> searchedAnime.cachedIn(viewModelScope)
    }
}

val explorationScreenState: StateFlow<ExploreScreenState> =
    combine(
        headerState,
        displayedStyle,
        displayedAnimeType,
    ) { headerState: HeaderScreenState, displayedStyle: DisplayStyle, displayedType: DisplayType ->
        ExploreScreenState(
            headerScreenState = headerState,
            displayStyle = displayedStyle,
            displayType = displayedType,
            anime = anime
        )
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.Eagerly,
        initialValue = ExploreScreenState()
    )

And here is my code for the lazy layout:

fun ExplorationScreen(
screenState: ExploreScreenState,
onEvent: (ExploreScreenEvent) -> Unit,
onAnimeClicked: (Anime) -> Unit,
modifier: Modifier = Modifier
) {
val pagingAnime: LazyPagingItems<Anime> = screenState.anime.collectAsLazyPagingItems()

val listOfLazyGridState: Map<DisplayType, LazyGridState> = mapOf(
    Pair(DisplayType.POPULAR, rememberLazyGridState()),
    Pair(DisplayType.AIRING, rememberLazyGridState()),
    Pair(DisplayType.UPCOMING, rememberLazyGridState())
)

val listOfLazyListState: Map<DisplayType, LazyListState> = mapOf(
    Pair(DisplayType.POPULAR, rememberLazyListState()),
    Pair(DisplayType.AIRING, rememberLazyListState()),
    Pair(DisplayType.UPCOMING, rememberLazyListState())
)
val lazyGridState = listOfLazyGridState[screenState.displayType]
val lazyListState = listOfLazyListState[screenState.displayType]

Scaffold(
    topBar = {
        // Top App Bar component
    },
    modifier = modifier
) { paddingValue ->

    if (pagingAnime.itemCount == 0 && screenState.displayType == DisplayType.SEARCH) {
        // Show error message when anime is not found on searching
        return@Scaffold
    }

    when (val refreshing = pagingAnime.loadState.refresh) {
        is LoadState.Error -> {
            // Show error message and retry button
            return@Scaffold
        }

        LoadState.Loading -> {
            // Show Loading Progress
            return@Scaffold
        }

        is LoadState.NotLoading -> {
            if (screenState.displayStyle == DisplayStyle.LIST) {
                LazyListAnime(
                    lazyListState = lazyListState ?: rememberLazyListState(),
                    pagingAnime = pagingAnime,
                    modifier = Modifier.padding(paddingValue),
                    onAnimeClicked = onAnimeClicked
                )
            } else {
                LazyGridAnime(
                    lazyGridState = lazyGridState ?: rememberLazyGridState(),
                    pagingAnime = pagingAnime,
                    screenState = screenState,
                    modifier = Modifier.padding(paddingValue),
                    onAnimeClicked = onAnimeClicked
                )
            }
        }
    }
}

}

Is there anything wrong with my way? and also my lazy layout feels really janky compared to xml. Here is the repository since i can't include everything in here: Lelenime Repository. The ui component was on Core:Common module and Feature module

Upvotes: 1

Views: 847

Answers (1)

Ujjwal Kumar Maharana
Ujjwal Kumar Maharana

Reputation: 289

This is a known issue in Paging library.
You can use following workaround at the moment

First create a extension function

@Composable
fun <T : Any> LazyPagingItems<T>.rememberLazyListState(): LazyListState {
    // After recreation, LazyPagingItems first return 0 items, then the cached items.
    // This behavior/issue is resetting the LazyListState scroll position.
    // Below is a workaround. More info: https://issuetracker.google.com/issues/177245496.
    return when (itemCount) {
        // Return a different LazyListState instance.
        0 -> remember(this) { LazyListState(0, 0) }
        // Return rememberLazyListState (normal case).
        else -> androidx.compose.foundation.lazy.rememberLazyListState()
    }
}

Then create lazyListState for your lazyPagingItems

val pagingAnimeScrollState = pagingAnime.rememberLazyListState()

Then in your lazyColumn pass this in state parameter.

This should fix your issue

Upvotes: 0

Related Questions