有没有办法通过使用 FirestoreRecyclerAdapter 组合查询游标来对查询进行分页?

Posted

技术标签:

【中文标题】有没有办法通过使用 FirestoreRecyclerAdapter 组合查询游标来对查询进行分页?【英文标题】:Is there a way to paginate queries by combining query cursors using FirestoreRecyclerAdapter? 【发布时间】:2018-11-08 13:54:25 【问题描述】:

我的查询如下所示:

Query first = ref.orderBy("name", Query.Direction.ASCENDING).limit(10);

这就是我将数据显示到我的RecyclerView 的方式。

firestoreRecyclerOptions = new FirestoreRecyclerOptions.Builder<ModelClass>().setQuery(query, ModelClass.class).build();
myFirestoreRecyclerAdapter = new MyFirestoreRecyclerAdapter(firestoreRecyclerOptions);
recyclerView.setAdapter(myFirestoreRecyclerAdapter);

我正在尝试使用here 中指定的分页,但无法解决。

first.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() 
    @Override
    public void onSuccess(QuerySnapshot documentSnapshots) 
        DocumentSnapshot lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() - 1);
        Query second = ref.orderBy("name", Query.Direction.ASCENDING).startAfter(lastVisible).limit(10);
        //Create a firestoreRecyclerOptions and setting the adapter
    
);

有没有办法通过使用FirestoreRecyclerAdapter 组合查询游标来对查询进行分页?这甚至可能吗?

【问题讨论】:

***.com/questions/43289731/… @Eminem 感谢您的评论。这也适用于 Cloud Firestore 吗?在那个例子中,我看不到FirebaseRecyclerAdapter 的用法,这几乎是一样的。 ***.com/questions/46795445/… @Eminem 我研究了上一篇文章并没有帮助我。你还有别的想法吗?谢谢! @Eminem 你能仔细看看我的问题吗?谢谢 【参考方案1】:

正如@FrankvanPuffelen 已经在您之前的@​​987654321@ 中回答的那样,您无法做到这一点,因为在您的情况下,您应该将 2 个不同的查询(firstsecond)传递给单个适配器,这是不可能的与FirestoreRecyclerAdapter。您可以将第一个查询或第二个查询与适配器的单个实例一起使用。

一种解决方案是创建两个不同的列表,其中包含每个查询的结果并将它们组合起来。然后您可以将结果列表传递给另一个适配器,比如说ArrayAdapter,然后将结果显示到ListView 中,甚至更好地显示在RecyclerView 中。这种情况下的问题是您将无法使用FirestoreRecyclerAdapter 类提供的实时功能,但这种方法将解决您的问题。

编辑:

根据您在评论部分的要求,我将举例说明如何使用ListViewArrayAdapter 以最简单的方式对单击按钮的查询进行分页。向下滚动时,您也可以使用RecyclerView 来实现相同的目的。但是为了简单起见,假设我们有一个ListView 和一个Button,并且我们希望在每次单击按钮时将更多项目加载到列表中。为此,让我们首先定义视图:

ListView listView = findViewById(R.id.list_view);
Button button = findViewById(R.id.button);

假设我们有一个如下所示的数据库结构:

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;

    @Override
    public String toString()  return productName; 

现在,让我们定义一个查询,并将限制设置为3

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference productsRef = rootRef.collection("products");
Query firstQuery = productsRef.orderBy("productName", Query.Direction.ASCENDING).limit(3);

这意味着每次单击按钮时,我们都会再加载 3 个项目。现在,这里是神奇的代码:

firstQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() 
    @Override
    public void onComplete(@NonNull Task<QuerySnapshot> task) 
        if (task.isSuccessful()) 
            List<ProductModel> list = new ArrayList<>();
            for (DocumentSnapshot document : task.getResult()) 
                ProductModel productModel = document.toObject(ProductModel.class);
                list.add(productModel);
            
            ArrayAdapter<ProductModel> arrayAdapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, list);
            listView.setAdapter(arrayAdapter);
            lastVisible = task.getResult().getDocuments().get(task.getResult().size() - 1);

            button.setOnClickListener(new View.OnClickListener() 
                @Override
                public void onClick(View view) 
                    Query nextQuery = productsRef.orderBy("productName", Query.Direction.ASCENDING).startAfter(lastVisible).limit(3);
                    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);
                                
                                arrayAdapter.notifyDataSetChanged();
                                lastVisible = t.getResult().getDocuments().get(t.getResult().size() - 1);
                            
                        
                    );
                
            );
        
    
);

其中lastVisible 是一个DocumentSnapshot 对象,表示查询中的最后一个可见项。在这种情况下,每三分之一,它被声明为 gloabl 变量:

private DocumentSnapshot lastVisible;

编辑2: Here 您还可以解决如何从 Firestore 数据库中获取数据并在用户滚动时将其以较小的块显示在 RecyclerView 中。

【讨论】:

你是说我无法使用FirestoreRecyclerAdapter 不,按照您尝试的方式。您应该考虑使用其他方法。 这基本上是另一个问题,但是好的,为了更好地理解,我会写几行代码。 请查看我的更新答案并告诉我它是否有效。 对不起,我忘了提。是的,它被声明为全局变量。请再次查看我的更新答案。【参考方案2】:

一种可能的方法是将每个项目的按键保存在单独的节点中。

然后从该节点获取所有键到数组列表或其他东西..

然后根据你的分页号从这个数组 List 中获取键,并使用 orderByKey 查询和 startAt 和 LimitToFirst 查询组合来制作分页算法

【讨论】:

嗨,保罗,感谢您的回答。我没有使用按键,我使用的是新的 Cloud Firestore 数据库。这里没有按键。您的想法在使用 Firebase 实时数据库时应该可行,但有什么方法可以使用 FirestoreRecyclerAdapter 实现这一点? 我不知道这是否正确将变量 second 更改为简单地 first 然后在任何按钮按下或执行 first.get().addOnSuccessListener 行时,可能会这样工作 请给我一个具体的例子。我没听懂你的意思。 请添加您当前实现的源代码,问题似乎不完整 我从头开始添加代码。这是一个简单的例子。

以上是关于有没有办法通过使用 FirestoreRecyclerAdapter 组合查询游标来对查询进行分页?的主要内容,如果未能解决你的问题,请参考以下文章