I want to paginate data from Firestore, using RecyclerView when I scroll I want to fetch new documents when all items are seen
here is my implementation : what's happening in my implementation is when I switch to the fragment which contains the recycler view, it loads data in chunks with a limit of 10,10,10... but all at once even when I do not scroll it, it loads all chunks at once.
di ->
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideQueryByName() = FirebaseFirestore.getInstance()
.collectionGroup(Constants.POSTS_COLLECTION).whereEqualTo("doc_id",
"jetpack")
.orderBy(Constants.POSTS_ORDER_BY,
Query.Direction.DESCENDING).limit(Constants.PAGE_SIZE.toLong())
}
paging source - >
class FirestorePagingSource (
private val queryProductsByName: Query
) : PagingSource<QuerySnapshot, PostsModel>() {
override fun getRefreshKey(state: PagingState<QuerySnapshot,
PostsModel>): QuerySnapshot? {
return null
}
override suspend fun load(params: LoadParams<QuerySnapshot>): LoadResult<QuerySnapshot, PostsModel> {
return try {
val currentPage = params.key ?: queryProductsByName.get().await()
Log.e("data",currentPage.size().toString())
val lastVisibleProduct = currentPage.documents[currentPage.size() - 1]
val nextPage = queryProductsByName.startAfter(lastVisibleProduct).get().await()
LoadResult.Page(
data = currentPage.toObjects(PostsModel::class.java),
prevKey = null,
nextKey = nextPage
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
adapter ->
class PostsAdapter : PagingDataAdapter<PostsModel, PostsAdapter.PostsViewHolder>(Companion) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostsViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val dataBinding = PostsDataBinding.inflate(
layoutInflater,
parent,
false
)
return PostsViewHolder(dataBinding)
}
override fun onBindViewHolder(holder: PostsViewHolder, position: Int) {
val product = getItem(position) ?: return
holder.bindProduct(product)
val density = Resources.getSystem().displayMetrics.density
if (position == 0) {
holder.itemView.layoutParams.height = 420 * density.toInt()
} else {
holder.itemView.layoutParams.height = 450 * density.toInt()
}
}
companion object : DiffUtil.ItemCallback<PostsModel>() {
override fun areItemsTheSame(oldItem: PostsModel, newItem: PostsModel): Boolean {
return oldItem.upload_date == newItem.upload_date
}
override fun areContentsTheSame(oldItem: PostsModel, newItem: PostsModel): Boolean {
return oldItem == newItem
}
}
inner class PostsViewHolder(
private val dataBinding: PostsDataBinding
) : RecyclerView.ViewHolder(dataBinding.root) {
fun bindProduct(product: PostsModel) {
dataBinding.posts = product
}
}
}
view model ->
@HiltViewModel
class PostsViewModel @Inject constructor(
private val queryPostsByName: Query
) : ViewModel() {
val flow = Pager(
PagingConfig(
pageSize = 10
)
) {
FirestorePagingSource(queryPostsByName)
}.flow.cachedIn(viewModelScope)
}
fragment ->
private fun setProgressBarAccordingToLoadState() {
dataBinding.rvUserPosts.adapter = adapter
}
private fun getPosts() {
lifecycleScope.launch {
viewModel2.flow.collectLatest {
adapter.submitData(it)
}
}
}
private fun setPostsAdapter() {
lifecycleScope.launch {
adapter.loadStateFlow.collectLatest {
dataBinding.progressBar.isVisible = it.append is LoadState.Loading
}
}
}
recycler view item ->
<?xml version="1.0" encoding="utf-8"?>
<data class="PostsDataBinding">
<variable
name="posts"
type="com.ansh.jetpack.mvvm.data.PostsModel" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="2dp"
app:cardCornerRadius="8dp">
<ImageView
android:id="@+id/ivCover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:imageUrl="@{posts.img_hd_url}"
android:src="@color/cardview_dark_background" />
</androidx.cardview.widget.CardView>
recycler view ->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvUserPosts"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager=
"androidx.recyclerview.widget.StaggeredGridLayoutManager"
app:spanCount="2"
tools:listitem="@layout/rv_user_posts_item" />