Java Firestore分页
我有一个关于如何使用Firestore正确分页查询的问题 通过将下一个查询放入上一个查询的OnSuccessListener,就像Firestore页面上的示例一样,它是否总是不可避免地触发一个连锁反应,一次加载所有页面?这不是我们想要避免的分页吗Java Firestore分页,java,android,firebase,google-cloud-firestore,Java,Android,Firebase,Google Cloud Firestore,我有一个关于如何使用Firestore正确分页查询的问题 通过将下一个查询放入上一个查询的OnSuccessListener,就像Firestore页面上的示例一样,它是否总是不可避免地触发一个连锁反应,一次加载所有页面?这不是我们想要避免的分页吗 // Construct query for first 25 cities, ordered by population Query first = db.collection("cities") .orderBy("populat
// 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
// ...
}
});
您必须在recyclerview/listview中使用ScrollListener。在开始时,您正在获取25个数据限制,一旦用户再次滚动到页面的末尾,您必须使用限制进行新的firestore调用,无论您保留什么。但此时,您必须在查询中继续使用startAt。startAt的输入将是第一次获取数据的最后一个键。这只是基本概述。 您可以参考链接进行查询 您可以使用firestore在recyclerview/listview中创建分页,如下所示: 基本上遵循以下步骤: 1在打开活动/片段时,您的第一次查询将获取25个数据限制
Query first = db.collection("cities")
.orderBy("population")
.limit(25);
first.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
// add data to recyclerView/listview
// Get the last visible document
DocumentSnapshot lastVisible = documentSnapshots.getDocuments()
.get(documentSnapshots.size() -1);
}
});
2现在覆盖适配器的onScrollListener
boolean isEndChildResults = false;
mRecyclerView.addOnScrollListener(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);
currentVisibleItem = linearLayoutManager.getChildCount();
totalItem = linearLayoutManager.getItemCount();
scrolledItem = linearLayoutManager.findFirstVisibleItemPosition();
if (isScrolling && (currentVisibleItem + scrolledItem == totalItem) && !isEndChildResults && documentSnapshot != null) {
isScrolling = false;
mProgressBarScroll.setVisibility(View.VISIBLE);
FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
Query query = firebaseFirestore.collection(...).document(...).limit(25).orderBy(...).startAt(lastVisible);
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
// add data to recyclerView/listview
lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() -1);
if (task.getResult().size() < postPerPageLimit) {
// if your result size is less than your query size which means all the result has been displayed and there is no any other data to display
isEndChildResults = true;
}
}
}
}
});
if(isEndChildResults){
// show snackbar/toast
}
}
*lastVisible documentSnapshot将在每个滚动上更改,它将从lastVisible snapshot获取数据您必须在recyclerview/listview中使用ScrollListener。在开始时,您正在获取25个数据限制,一旦用户再次滚动到页面的末尾,您必须使用限制进行新的firestore调用,无论您保留什么。但此时,您必须在查询中继续使用startAt。startAt的输入将是第一次获取数据的最后一个键。这只是基本概述。 您可以参考链接进行查询 您可以使用firestore在recyclerview/listview中创建分页,如下所示: 基本上遵循以下步骤: 1在打开活动/片段时,您的第一次查询将获取25个数据限制
Query first = db.collection("cities")
.orderBy("population")
.limit(25);
first.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
// add data to recyclerView/listview
// Get the last visible document
DocumentSnapshot lastVisible = documentSnapshots.getDocuments()
.get(documentSnapshots.size() -1);
}
});
2现在覆盖适配器的onScrollListener
boolean isEndChildResults = false;
mRecyclerView.addOnScrollListener(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);
currentVisibleItem = linearLayoutManager.getChildCount();
totalItem = linearLayoutManager.getItemCount();
scrolledItem = linearLayoutManager.findFirstVisibleItemPosition();
if (isScrolling && (currentVisibleItem + scrolledItem == totalItem) && !isEndChildResults && documentSnapshot != null) {
isScrolling = false;
mProgressBarScroll.setVisibility(View.VISIBLE);
FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
Query query = firebaseFirestore.collection(...).document(...).limit(25).orderBy(...).startAt(lastVisible);
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
// add data to recyclerView/listview
lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() -1);
if (task.getResult().size() < postPerPageLimit) {
// if your result size is less than your query size which means all the result has been displayed and there is no any other data to display
isEndChildResults = true;
}
}
}
}
});
if(isEndChildResults){
// show snackbar/toast
}
}
*lastVisible documentSnapshot将在每个滚动上更改,它将从lastVisible snapshot获取数据构造查询时不会从该查询中读取数据 所以这段代码只创建了一个查询:
Query next = db.collection("cities")
.orderBy("population")
.startAfter(lastVisible)
.limit(25);
它不会从数据库中读取任何数据。这意味着它也不会触发任何onSuccess方法
如果您立即下一个.get.addOnSuccessListener。。。实际上,您将创建一个加载所有页面的循环。构造查询还不会从该查询中读取数据 所以这段代码只创建了一个查询:
Query next = db.collection("cities")
.orderBy("population")
.startAfter(lastVisible)
.limit(25);
它不会从数据库中读取任何数据。这意味着它也不会触发任何onSuccess方法
如果您立即下一个.get.addOnSuccessListener。。。您确实需要创建一个加载所有页面的循环。但是上面显示的示例在第一个查询的OnSuccessListener中检索下一个查询,因此在这个匿名类之外它不可用。@FlorianWalther我已经更新了我的答案,如果您还有任何疑问,请告诉我。谢谢,但是lastVisible必须是一个成员变量,对吗?因为现在它是在第一个OnSuccessListener@FlorianWalther是的,它必须是成员变量。@RohitMaurya也许你也可以看看。谢谢但是上面显示的示例在第一个查询的OnSuccessListener中检索下一个查询,因此在这个匿名类之外它不可用。@FlorianWalther我已经更新了我的答案,如果您还有任何疑问,请告诉我。谢谢,但是lastVisible必须是一个成员变量,对吗?因为现在它是在第一个OnSuccessListener@FlorianWalther是的,它必须是成员变量。@RohitMaurya也许你也可以看看。谢谢但是查询变量是在匿名内部类中声明的,因此它是&39;从外面是无法到达的,对吗?那么我以后如何使用它呢?这只是一个如何构造这样一个查询的示例。所以在一个真实的示例中,我们将下一个查询存储在一个成员变量中?这是一种方法。或者在成员中保持lastVisible,并在需要时构造查询。是的,我是说lastVisible,对不起。如果还没有查询,这个变量将为null,因此如果我想让同一个按钮执行第一次加载以及所有后续加载,我将进行null检查,并根据结果创建两个不同的查询?一个查询有startAfter,一个查询没有。但是查询变量是在匿名内部类中声明的,因此它是&39;从外面是无法到达的,对吗?那么我以后如何使用它呢?这只是一个如何构造这样一个查询的示例。所以在一个真实的示例中,我们将下一个查询存储在一个成员变量中?这是一种方法。或者在成员中保持lastVisible,并在需要时构造查询。是的,我是说lastVisible,对不起。如果还没有查询,这个变量将为null,因此如果我想让同一个按钮执行第一次加载以及所有后续加载,我将进行null检查,并根据结果创建两个不同的查询?一个带startAfter的查询和一个不带startAfter的查询。你解决了这个问题吗?有人告诉我我的方法很好,它对你有用吗?是的,它与exac一起工作
你的问题中的t代码?你解决了这个问题吗?我被告知我的方法很好,它对你有效吗?是的,它与你问题中的精确代码有效吗?