You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVVM架构下Firestore瀑布流RecyclerView分页加载异常排查

Firestore分页加载异常:切换Fragment时一次性加载所有数据块

需求:实现Firestore数据分页加载,滚动RecyclerView至底部时获取新文档。
问题:切换到包含RecyclerView的Fragment时,会一次性加载所有10条一组的数据块,而非按需滚动加载。


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())
}

PagingSource实现

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
    }
  }
 }

ViewModel实现

@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
        }
    }
}

RecyclerView 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>

RecyclerView布局

<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" />

内容的提问来源于stack exchange,提问作者Himanshu Yadav Anshu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 16:00:28