1

I am having a problem using new Paging 3 library in Android, as it loads all pages at once. I read this post: Android Paging (3) load all pages at once

But in my case, RecyclerView is not inside any infinite scroller (Nested), but simply inside parent ConstraintLayout and it is scrolling horizontally! I have tried a lot of things, considering to return my default implementation(not using this nice API). Here is my code example:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/clDashboardMain"
    android:background="@color/white"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/spacing_24"
        android:clipToPadding="false"
        android:orientation="horizontal"
        android:paddingStart="@dimen/spacing_24"
        android:paddingEnd="@dimen/spacing_24"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

MyRepository:

   override fun getData(latitude: Double, longitude: Double): LiveData<PagingData<DataPost>> {
         return Pager(
                config = PagingConfig(
                        pageSize = NETWORK_PAGE_SIZE, //is 20!
                        enablePlaceholders = false
                ),
                pagingSourceFactory = {
                    GetPagingSource(myApiService = myApiService, latitude = latitude, longitude = longitude)
                }
        ).liveData
    }

My PagingSource file:

private const val INITIAL_LOAD_SIZE = 1

class GetPagingSource(
        private val myApiService: MyApiService,
        private val latitude: Double,
        private val longitude: Double
        ) : PagingSource<Int, DataPost>() {
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, DataPost> {

        // Retrofit calls that return the body type throw either IOException for network
        // failures, or HttpException for any non-2xx HTTP status codes. This code reports all
        // errors to the UI, but you can inspect/wrap the exceptions to provide more context.
        return try {
            // Key may be null during a refresh, if no explicit key is passed into Pager
            // construction. Use 1 as default, because our API is indexed started at index 0
            val pageNumber = params.key ?: INITIAL_LOAD_SIZE

            // Suspending network load via Retrofit. This doesn't need to be wrapped in a
            // withContext(Dispatcher.IO) { ... } block since Retrofit's Coroutine
            // CallAdapter dispatches on a worker thread.
            val response = myApiService.getData(latitude = latitude, longitude = longitude, page= pageNumber)

            // Since 0 is the lowest page number, return null to signify no more pages should be loaded before it.
            val prevKey = if (pageNumber == INITIAL_LOAD_SIZE) null else pageNumber - 1

            // This API defines that it's out of data when a page returns empty. When out of data, we return `null` to signify no more pages should be loaded
            val nextKey = if (response.data.isNotEmpty()) pageNumber + 1 else null
            LoadResult.Page(
                    data = response.data.filter { it.coordinates.longitude > 0.0 },
                    prevKey = prevKey,
                    nextKey = nextKey
            )
        } catch (e: IOException) {
            LoadResult.Error(e)
        } catch (e: HttpException) {
            LoadResult.Error(e)
        }
    }

    override fun getRefreshKey(state: PagingState<Int, DataPost>): Int? {
        return state.anchorPosition?.let {
            state.closestPageToPosition(it)?.prevKey?.plus(1)
                    ?: state.closestPageToPosition(it)?.nextKey?.minus(1)
        }
    }
}

My viewmodel:

 //live data use case
    fun getData(latitude: Double, longitude: Double): LiveData<PagingData<DataPostUIWrapper>> {
        val currentLoggedUser = profileContract.getUserProfileId()

        return postsContract.getPublicPosts(latitude, longitude)
                .map {
                    it.map { dataPost ->
                        DataPostUIWrapper(dataPost, dataPost.isLikedBy(currentLoggedUser))
                    }
                }
                .cachedIn(viewModelScope)
    }

Observing on UI:

  viewModel.getData(latitude = userLocation.latitude, longitude = userLocation.longitude).observe(viewLifecycleOwner, {
                lifecycleScope.launch {
                    myAdapter.submitData(it)
                }
            })
DM developing
  • 423
  • 5
  • 15
  • Hi, I've used `Paging-3` before, if you could add the complete code as a github link i can check once and let you know about the issue :) – mehul bisht Jul 18 '21 at 10:10
  • Hi! It is very hard to post on git as it is a lot of other logic code in. If I manage to do it, I will let you know! – DM developing Jul 18 '21 at 10:32
  • why not just place it within an infinite scroller? then it should just work right? – Ryan Jul 18 '21 at 11:38
  • Ryan. What's the point then using RV? It is intended for performance and with combo Paging v3, it should be easy. – DM developing Jul 18 '21 at 17:07

2 Answers2

0

It's happened because Paging Adapter can't resolve anchor.

Evgenii
  • 105
  • 1
  • 9
-1

In my case, I was using room and this recipeId data type was long, that took me five days to find out but when I changed it to string it works fine.

@Entity(tableName = "table_recipe")
data class RecipeList(
        @PrimaryKey
        @field:SerializedName("recipe_id") var recipeId : String,
        @field:SerializedName("title") var title: String? = null,
)
Dmytro Rostopira
  • 10,588
  • 4
  • 64
  • 86