私は、Firestoreのページネーションについてのインターネット上のすべての記事(stackoverflow)を読んでいますが、運はありません。ドキュメントに正確なコードを実装しようとしましたが、何も起こりません。アイテム(1250以上)を含む基本的なデータベースがあり、それらを段階的に取得したいです。スクロールして15個のアイテムを(データベースの最後のアイテムまで)ロードします。
ドキュメントコードを使用する場合:
// 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:ユーザーがスクロールするときに、リストビューではなくリサイクラビューが必要です。ありがとう
公式ドキュメント で述べられているように、この問題を解決するための鍵は 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
という1つのビューのみが含まれます。
<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()
を使用する必要があります。 。
FirebaseUI-Androidも最近Firestore Paginatorを発表しました。
私はコードでそれを使用しましたが、うまく機能します-.addSnapshotListener()の代わりに.get()を使用して動作するため、リサイクラはリアルタイムではありません。
こちらのドキュメントをご覧ください。