我阅读了Firestore文档以及关于Firestore分页的互联网(stackoverflow)上的所有文章,但没有运气。我试图在docs中实现确切的代码,但没有任何反应。我有一个基本的数据库项目(超过1250或更多),我想逐步得到它们。通过滚动来加载15个项目(到数据库中的最后一项)。
如果使用docs代码:
// Construct query for first 25 cities, ordered by population
Query first = db.collection("cities")
.orderBy("population")
.limit(25);
first.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
// ...
// Get the last visible document
DocumentSnapshot lastVisible = documentSnapshots.getDocuments()
.get(documentSnapshots.size() -1);
// Construct a new query starting at this document,
// get the next 25 cities.
Query next = db.collection("cities")
.orderBy("population")
.startAfter(lastVisible)
.limit(25);
// Use the query for pagination
// ...
}
});
怎么办?文档没有太多细节。
PS:当用户滚动时,我需要使用回收站视图(不是列表视图)。感谢
答案 0 :(得分:16)
正如official documentation中提到的,解决此问题的关键是使用startAfter()方法。因此,您可以通过将查询游标与limit()
方法相结合来对查询进行分页。您将能够将批处理中的最后一个文档用作下一批的游标的开头。
要解决这个分页问题,请参阅我的回答 post ,我已逐步解释了如何从较小的块中加载Cloud Firestore数据库中的数据并在点击按钮ListView
上显示。
<强>解决方案:强>
要从Firestore数据库获取数据并在RecyclerView
中以较小的块显示,请按照以下步骤操作。
我们来看上面使用过产品的例子。您可以使用产品,城市或任何您想要的东西。原则是一样的。假设您想在用户滚动时加载更多产品,我将使用RecyclerView.OnScrollListener
。
让我们首先定义RecyclerView
,将布局管理器设置为LinearLayoutManager
并创建一个列表。我们还使用空列表实例化适配器并将适配器设置为我们的RecyclerView
:
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
List<ProductModel> list = new ArrayList<>();
ProductAdapter productAdapter = new ProductAdapter(list);
recyclerView.setAdapter(productAdapter);
假设我们有一个如下所示的数据库结构:
Firestore-root
|
--- products (collection)
|
--- productId (document)
|
--- productName: "Product Name"
一个看起来像这样的模型类:
public class ProductModel {
private String productName;
public ProductModel() {}
public ProductModel(String productName) {this.productName = productName;}
public String getProductName() {return productName;}
}
这个适配器类应该是这样的:
private class ProductAdapter extends RecyclerView.Adapter<ProductViewHolder> {
private List<ProductModel> list;
ProductAdapter(List<ProductModel> list) {
this.list = list;
}
@NonNull
@Override
public ProductViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_product, parent, false);
return new ProductViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ProductViewHolder productViewHolder, int position) {
String productName = list.get(position).getProductName();
productViewHolder.setProductName(productName);
}
@Override
public int getItemCount() {
return list.size();
}
}
item_product
布局只包含一个视图,TextView
。
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text_view"
android:textSize="25sp"/>
这就是持有人类应该是这样的:
private class ProductViewHolder extends RecyclerView.ViewHolder {
private View view;
ProductViewHolder(View itemView) {
super(itemView);
view = itemView;
}
void setProductName(String productName) {
TextView textView = view.findViewById(R.id.text_view);
textView.setText(productName);
}
}
现在,让我们将限制定义为全局变量,并将其设置为15
。
private int limit = 15;
现在让我们使用这个限制来定义查询:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference productsRef = rootRef.collection("products");
Query query = productsRef.orderBy("productName", Query.Direction.ASCENDING).limit(limit);
以下代码在您的案例中也具有魔力:
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
ProductModel productModel = document.toObject(ProductModel.class);
list.add(productModel);
}
productAdapter.notifyDataSetChanged();
lastVisible = task.getResult().getDocuments().get(task.getResult().size() - 1);
RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true;
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager linearLayoutManager = ((LinearLayoutManager) recyclerView.getLayoutManager());
int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
int visibleItemCount = linearLayoutManager.getChildCount();
int totalItemCount = linearLayoutManager.getItemCount();
if (isScrolling && (firstVisibleItemPosition + visibleItemCount == totalItemCount) && !isLastItemReached) {
isScrolling = false;
Query nextQuery = productsRef.orderBy("productName", Query.Direction.ASCENDING).startAfter(lastVisible).limit(limit);
nextQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> t) {
if (t.isSuccessful()) {
for (DocumentSnapshot d : t.getResult()) {
ProductModel productModel = d.toObject(ProductModel.class);
list.add(productModel);
}
productAdapter.notifyDataSetChanged();
lastVisible = t.getResult().getDocuments().get(t.getResult().size() - 1);
if (t.getResult().size() < limit) {
isLastItemReached = true;
}
}
}
});
}
}
};
recyclerView.addOnScrollListener(onScrollListener);
}
}
});
其中lastVisible
是DocumentSnapshot
对象,表示查询中的最后一个可见项。在这种情况下,每15个一个,它被声明为gloabl变量:
private DocumentSnapshot lastVisible;
isScrolling
和isLastItemReached
也是全局变量,声明为:
private boolean isScrolling = false;
private boolean isLastItemReached = false;
如果您想实时获取数据,那么您需要使用get()
,而不是使用addSnapshotListener()
调用,如有关listening to multiple documents in a collection的官方文档中所述。
答案 1 :(得分:2)
FirebaseUI-Android最近还推出了Firestore Paginator。
我在我的代码中使用过它,并且效果很好 - 请记住它使用.get()而不是.addSnapshotListener()进行操作,因此回收器不是实时的。
请参阅此处的文档:
答案 2 :(得分:0)
您还可以使用Firebase-UI-Firestore提供的{
"vehicleNumber": "1231",
"customerName": "123",
"customerMobileNumber": 1231232312,
"createdOn": null,
"total": 23123,
"billItems": [
{
"itemName": "1231",
"cost": 23123,
"id": "9510"
}
],
"id": 467
}
您需要安装此依赖项
FirestorePagingAdapter
步骤1:创建一个全局Firestore分页适配器变量,并传递Model类和ViewHolder以及Model变量。
implementation 'com.firebaseui:firebase-ui-firestore:latest_version_here'
步骤2: 创建Firebase查询
private FirestorePagingAdapter<Model, ModelViewHolder> adapter;
private Model model;
步骤3: 让我们构建pagedlist配置。在这里您将传递每页要查询的数据量;
Query query = db.collection("cities")
.orderBy("population");
第4步:设置好配置后,我们现在构建Firestore分页选项,您将在其中传递PagedList.Config config = new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setPrefetchDistance(10)
.setPageSize(15)
.build();
和query
。
config
步骤:5 现在,将数据传递到Recylerview
FirestorePagingOptions<Model> options = new FirestorePagingOptions.Builder<Model>()
.setLifecycleOwner(this)
.setQuery(query, config, snapshot -> {
model = snapshot.toObject(Model.class);
return model;
})
.build();
快乐编码!