3

I have two queries:

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

Query secondQuery = ref.orderBy("price", Query.Direction.ASCENDING).limit(10);
getMoreData(secondQuery);

The first method looks like this:

private void getData(Query query) {
    firestoreRecyclerOptions = new FirestoreRecyclerOptions.Builder<ModelClass>().setQuery(query, ModelClass.class).build();
    myFirestoreRecyclerAdapter = new MyFirestoreRecyclerAdapter(firestoreRecyclerOptions);
    recyclerView.setAdapter(myFirestoreRecyclerAdapter);
}

And here is the second method.

private void getMoreData(Query query) {
    firestoreRecyclerOptions = new FirestoreRecyclerOptions.Builder<ModelClass>().setQuery(query, ModelClass.class).build();
    myFirestoreRecyclerAdapter = new MyFirestoreRecyclerAdapter(firestoreRecyclerOptions);
    recyclerView.setAdapter(myFirestoreRecyclerAdapter);
}

Both variables are declared as global:

private FirestoreRecyclerOptions<ModelClass> firestoreRecyclerOptions;
private MyFirestoreRecyclerAdapter myFirestoreRecyclerAdapter;

When the app starts, the elements are displayed in the RecyclerView using the first method. What I want to achieve is that on a button click, when the getMoreData() method is triggered to add the result from the second query in the same adapter, ending up having 20 elements. Now, when I click the button, the elements from the second query will override the first ones.

Joan P.
  • 2,368
  • 6
  • 30
  • 63

2 Answers2

1

There is nothing built-in to combine two queries in a FirestoreRecyclerAdapter.

The best I can think of is creating a List/array of the combined results in your app code and then using an array adapter. It's not ideal, since you won't be using FirebaseUI.

Alternatively, have a look at FirebaseUIs FirestorePagingAdapter, which combines multiples pages of (non-realtime) DocumentSnapshots in a single recycler view.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • 1
    I thought I'll find a possibility to combine those two queries since both return objects of the same type. But now knowing what you said, I'm trying to find another way. Reading also [this](https://stackoverflow.com/questions/50273741/firestorepagingadapter-not-receiving-realtime-updates), I understand that the second option will also not help me. Thank you! – Joan P. May 29 '18 at 19:52
0

I ended up using a modified version of adapter class from the Friendly-eats code lab sample.

The following class allows you add an initial query and then set another one using the FirestoreAdapter.setQuery(query) method.

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.firestore.*
import com.google.firebase.firestore.EventListener
import java.util.*

/**
 * RecyclerView adapter for displaying the results of a Firestore [Query].
 *
 * Note that this class forgoes some efficiency to gain simplicity. For example, the result of
 * [DocumentSnapshot.toObject] is not cached so the same object may be deserialized
 * many times as the user scrolls.
 *
 *
 * See the adapter classes in FirebaseUI (https://github.com/firebase/FirebaseUI-Android/tree/master/firestore) for a
 * more efficient implementation of a Firestore RecyclerView Adapter.
 */
abstract class FirestoreAdapter<VH : RecyclerView.ViewHolder>(private var query: Query,
                                                              private val lifecycleOwner: LifecycleOwner)
  : RecyclerView.Adapter<VH>(), EventListener<QuerySnapshot>, LifecycleObserver {

  private var listener: ListenerRegistration? = null
  private val snapshots = ArrayList<DocumentSnapshot>()

  @OnLifecycleEvent(Lifecycle.Event.ON_START)
  fun startListening() {
    if (listener == null) {
      listener = query.addSnapshotListener(this)
    }
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
  fun stopListening() {
    listener?.apply {
      remove()
      listener = null
    }

    snapshots.clear()
    notifyDataSetChanged()
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
  internal fun cleanup(source: LifecycleOwner) {
    source.lifecycle.removeObserver(this)
  }

  override fun onEvent(snapshot: QuerySnapshot?, error: FirebaseFirestoreException?) {
    when {
      error != null -> onError(error)
      else -> {
        // Dispatch the event
        snapshot?.apply {
          for (change in documentChanges) {
            when (change.type) {
              DocumentChange.Type.ADDED -> onDocumentAdded(change)
              DocumentChange.Type.MODIFIED -> onDocumentModified(change)
              DocumentChange.Type.REMOVED -> onDocumentRemoved(change)
            }
          }
          onDataChanged()
        }
      }
    }
  }

  protected fun onDocumentAdded(change: DocumentChange) {
    snapshots.add(change.newIndex, change.document)
    notifyItemInserted(change.newIndex)
  }

  protected fun onDocumentModified(change: DocumentChange) {
    if (change.oldIndex == change.newIndex) {
      // Item changed but remained in same position
      snapshots[change.oldIndex] = change.document
      notifyItemChanged(change.oldIndex)
    } else {
      // Item changed and changed position
      snapshots.removeAt(change.oldIndex)
      snapshots.add(change.newIndex, change.document)
      notifyItemMoved(change.oldIndex, change.newIndex)
    }
  }

  protected fun onDocumentRemoved(change: DocumentChange) {
    snapshots.removeAt(change.oldIndex)
    notifyItemRemoved(change.oldIndex)
  }

  fun setQuery(query: Query) {
    stopListening()

    // Clear existing data
    snapshots.clear()
    notifyDataSetChanged()

    // Listen to new query
    this.query = query
    startListening()
  }

  override fun getItemCount(): Int = snapshots.size

  protected fun getSnapshot(index: Int): DocumentSnapshot = snapshots[index]

  protected open fun onError(exception: FirebaseFirestoreException) {}

  protected open fun onDataChanged() {}
}
Marco RS
  • 8,145
  • 3
  • 37
  • 45