Как разбить Firestore на Android? - PullRequest
0 голосов
/ 07 июня 2018

Я прочитал документацию Firestore и все статьи в интернете (stackoverflow) о нумерации страниц Firestore, но не повезло.Я пытался реализовать точный код в документах, но ничего не происходит.У меня есть базовая база данных с предметами (более 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: мне нужно с представлением рециркулятора (не представлением списка), когда пользователь прокручивает.Спасибо

Ответы [ 2 ]

0 голосов
/ 09 июня 2018

FirebaseUI-Android также недавно выпустил Firestore Paginator.

Я использовал его в своем коде, и он прекрасно работает - просто имейте в виду, что он работает с использованием .get () вместо .addSnapshotListener (), поэтому утилита не работает в реальном времени.

См. Документы здесь:

https://github.com/firebase/FirebaseUI-Android/tree/master/firestore#using-the-firestorepagingadapter

0 голосов
/ 07 июня 2018

Как указано в официальной документации , ключом к решению этой проблемы является использование метода startAfter () .Таким образом, вы можете разбивать запросы на страницы, комбинируя курсоры запросов с помощью метода limit().Вы сможете использовать последний документ в пакете в качестве начала курсора для следующего пакета.

Чтобы решить эту проблему нумерации страниц, см. Мой ответ из этой записи , в котором я объяснил шаг за шагом, как вы можете загружать данные из базы данных 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-й и он объявляется как глобальная переменная:

private DocumentSnapshot lastVisible;

И isScrolling и isLastItemReached также являются глобальными переменными и объявляются как:

private boolean isScrolling = false;
private boolean isLastItemReached = false;

Если вы хотите получать данные в режиме реального времени, вместо звонка get() вам нужно использовать addSnapshotListener(), как объяснено в официальной документации относительно прослушивания нескольких документов в коллекции .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...