[英]how to paginate data in viewModel with recycler view in fragment using firestore
[英]How to paginate data from firestore with MVVM using staggered grid recycler view
我想对 Firestore 中的数据进行分页,滚动时使用 RecyclerView 我想在看到所有项目时获取新文档
这是我的实现:在我的实现中发生的事情是,当我切换到包含回收器视图的片段时,它会以块的形式加载数据,限制为 10、10、10 ......但即使我不滚动也是一次它,它一次加载所有块。
迪->
@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())
}
分页源->
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)
}
}
}
适配器->
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
}
}
}
查看 model ->
@HiltViewModel
class PostsViewModel @Inject constructor(
private val queryPostsByName: Query
) : ViewModel() {
val flow = Pager(
PagingConfig(
pageSize = 10
)
) {
FirestorePagingSource(queryPostsByName)
}.flow.cachedIn(viewModelScope)
}
片段->
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
}
}
}
回收站查看项目->
<?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>
回收站视图->
<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" />
我认识这段代码,你很可能是从这个资源中得到的:
由于我写了那篇文章和相应的 代码,我可以向你保证,它不会获取数据库中的所有数据,它只会加载一组 10 个文档,一个接一个。
为什么我认为您会一次获得所有数据? 这仅仅是因为您在数据库中没有足够的文档。
首次启动应用程序时,您会获得 10 个文档。 由于第一个屏幕可以容纳超过 10 个元素,实际上是 12 个,因此完成了另一个请求。 到目前为止,您收到了 20 个文档。 如文章中所述, Paging v3 库包含一个PagingConfig class,它有一个公共构造函数,其中包含一个名为prefetchDistance的参数:
预取距离,它定义了距离加载的内容访问边缘多远才能触发进一步加载。
这基本上意味着,该库会提前加载另外 10 个文档,因此您不会有滞后的体验。 因此,当第一次启动应用程序时,您请求 30 个文档,因为限制设置为 10。如果您在数据库中只有 30 个文档,是的,您正在下载它们,但是如果您有,例如, 100 个文档,您会看到,当您到达第 20 个文档时,又加载了 10 个文档,依此类推,直到您全部获得它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.