Search code examples
androidandroid-recyclerviewandroid-paging

Android Paging3 list items jumps to beginning of the screen and infinite loop


I have a recyclerview in my app and i wanted to make it work with Android paging3 library.Its kind of working but not the way i wanted. Here when i open the list, the number of data that i defined in PagingConfig.pageSize creating at the top. And when i keep contiune to scrool up it never stop like an infinite loop. But when i scroll down its working fine like this;

enter image description here

as you see scrolling up is always enabled.

I don't know what's the problem here my codes;

MyAdapter;

package com.tolgahantutar.bexworkfloww.ui.addressbook

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.Navigation
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.tolgahantutar.bexworkfloww.R
import com.tolgahantutar.bexworkfloww.data.models.userget.UserGetValue
import kotlinx.android.synthetic.main.contacts_layout.view.*

class UserAdapter() :
PagingDataAdapter<UserGetValue, UserAdapter.UserViewHolder>(DiffCallBack()) {

    class DiffCallBack : DiffUtil.ItemCallback<UserGetValue>(){
        override fun areItemsTheSame(oldItem: UserGetValue, newItem: UserGetValue): Boolean {
            return oldItem.name == newItem.name
        }

        override fun areContentsTheSame(oldItem: UserGetValue, newItem: UserGetValue): Boolean {
        return oldItem.name == newItem.name
        }

    }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.itemView.contac_name_textview.text =getItem(position)!!.name
        holder.itemView.user_profile_text_left_drawable.setText("${(getItem(position)!!.name.substringBefore(" ")).subSequence(0,1)}"+"${(getItem(position)!!.name.substringAfter(" ").subSequence(0,1))}")
        holder.itemView.contact_info_text.text = getItem(position)!!.title
        var getContactValue = getItem(position)!!
        holder.itemView.setOnClickListener {
            val action = AdressBookFragmentDirections.actionUserDetail(getItem(position)!!)
            Navigation.findNavController(it).navigate(action)
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        return UserViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.contacts_layout, parent, false)
        )
    }

    class UserViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {

    }

}

PagingSource;


import androidx.paging.PagingSource
import com.tolgahantutar.bexworkfloww.data.models.userget.UserGetValue
import com.tolgahantutar.bexworkfloww.data.network.apis.WorkFlowServicesApi

class UserRemotePagingSource(private val api : WorkFlowServicesApi): PagingSource<Int,UserGetValue>(){
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, UserGetValue> {
        return try {
            val page = params.key?: 1
            val response = api.userGet(2,page,2)
            LoadResult.Page(
                data = response.body()!!.userGetValue,
                prevKey = page-1,
                nextKey = page+1
            )
        }catch (e: Exception){
            LoadResult.Error(e)
        }
    }
} 

ViewModel;

fun usersPagingFlow(): Flow<PagingData<UserGetValue>>{
        return Pager(
            config = PagingConfig(
                pageSize = 2,
                prefetchDistance = 2,
                enablePlaceholders = true,
                initialLoadSize = 2*3
            )
        ){
            UserRemotePagingSource(api)
        }.flow
    } 

And Fragment ;

recycler_view_contacts.setHasFixedSize(true)
            recycler_view_contacts.adapter = pagingDataAdapter
        recycler_view_contacts.layoutManager = LinearLayoutManager(requireContext())

            lifecycleScope.launch {
                addressBookViewModel.usersPagingFlow().collectLatest { pagingData ->
                    pagingDataAdapter.submitData(pagingData)
                }
            } 

Solution

  • In your PagingSource implementation, it looks like you need to check when your key is 1, then set prevKey to null to mark the end of the list.

    It kind of looks like what's happening when you give your api a negative number, is that it just loads the first page again.