如何在 FirestoreRecyclerAdapter 中添加 2 个不同的查询?

Posted

技术标签:

【中文标题】如何在 FirestoreRecyclerAdapter 中添加 2 个不同的查询?【英文标题】:How to add 2 different queries inside an FirestoreRecyclerAdapter? 【发布时间】:2018-11-08 12:00:52 【问题描述】:

我有两个疑问:

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

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

第一种方法如下:

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

这是第二种方法。

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

两个变量都声明为全局变量:

private FirestoreRecyclerOptions<ModelClass> firestoreRecyclerOptions;
private MyFirestoreRecyclerAdapter myFirestoreRecyclerAdapter;

当应用启动时,使用第一种方法将元素显示在RecyclerView中。我想要实现的是,在单击按钮时,当触发 getMoreData() 方法以将第二个查询的结果添加到同一适配器中时,最终有 20 个元素。现在,当我单击按钮时,第二个查询中的元素将覆盖第一个。

【问题讨论】:

【参考方案1】:

FirestoreRecyclerAdapter 中组合两个查询没有任何内置功能。

我能想到的最好的方法是在您的应用代码中创建一个组合结果的List/array,然后使用数组适配器。这并不理想,因为您不会使用 FirebaseUI。

或者,看看FirebaseUIs FirestorePagingAdapter,它将(非实时)DocumentSnapshots 的多个页面组合在一个回收器视图中。

【讨论】:

我想我会找到组合这两个查询的可能性,因为它们都返回相同类型的对象。但现在知道你说了什么,我正试图找到另一种方法。还阅读this,我知道第二个选项也对我没有帮助。谢谢!【参考方案2】:

我最终使用了来自Friendly-eats code lab sample 的适配器类的修改版本。

以下类允许您添加一个初始查询,然后使用FirestoreAdapter.setQuery(query) 方法设置另一个查询。

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() 

【讨论】:

以上是关于如何在 FirestoreRecyclerAdapter 中添加 2 个不同的查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何在表单提交后保留文本(如何在提交后不删除自身?)

如何在异步任务中调用意图?或者如何在 onPostExecute 中开始新的活动?

在 Avkit 中如何使用这三行代码,以及如何将音乐静音”

如何在 JDBC 中启动事务?

如何在 Fragment 中调用 OnActivityResult 以及它是如何工作的?

如何使用 Firebase 在 Web 上托管 Flutter?它的效果如何?