来自 Firebase Firestore 的 Android 反应式列表

Posted

技术标签:

【中文标题】来自 Firebase Firestore 的 Android 反应式列表【英文标题】:Reactive list on Android from Firebase Firestore 【发布时间】:2021-12-30 02:26:48 【问题描述】:

我试图在从 Firestore 下载一些数据后更新 RecyclerView,但当数据更改时它似乎不会更新 UI。以下是主要活动:

class MainActivity : AppCompatActivity() 

private lateinit var dbService: DatabaseManager
private var mBound: Boolean = false

private val restaurantListModel: RestaurantList by viewModels()

val data = ArrayList<RestaurantCardModel>()
val adapter = RestaurantListAdapter(data)

/** Defines callbacks for service binding, passed to bindService()  */
private val connection = object : ServiceConnection 

    override fun onServiceConnected(className: ComponentName, service: IBinder) 

        // We've bound to LocalService, cast the IBinder and get LocalService instance
        val binder = service as DatabaseManager.LocalBinder
        dbService = binder.getService()
        mBound = true

        dbService.read_restaurants(object: MyCallback 
            override fun onCallback(value: MutableList<Restaurant>) 
                restaurantListModel.restList.value = value
                updateView()
            
        )
    

    override fun onServiceDisconnected(arg0: ComponentName) 
        mBound = false
    


fun updateView()
    for (rest in restaurantListModel.restList.value!!)
        data.add(RestaurantCardModel(R.drawable.pizza_express_logo, rest.name, 5, rest.review, rest.no_review,
            R.color.colorPrimary))
    


override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // Bind to LocalService
    Intent(this, DatabaseManager::class.java).also  intent ->
        bindService(intent, connection, Context.BIND_AUTO_CREATE)
    

    // getting the recyclerview by its id
    val recyclerview = findViewById<RecyclerView>(R.id.restaurant_recyclerview)

    // this creates a vertical layout Manager
    recyclerview.layoutManager = LinearLayoutManager(this)

    // Setting the Adapter with the recyclerview
    recyclerview.adapter = adapter
    
    if(mBound)  updateView() 


override fun onResume() 
    super.onResume()
    if (mBound)  updateView() 


override fun onStart() 
    super.onStart()


override fun onStop() 
    super.onStop()
    unbindService(connection)
    mBound = false

然后你有我的数据库管理器从 firebase 获取数据:

class DatabaseManager : Service() 
// Binder given to clients
private val binder = LocalBinder()

var db = FirebaseFirestore.getInstance()

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int 
    return super.onStartCommand(intent, flags, startId)


fun upload_review(review_data: String)



fun read_restaurants(myCallback : MyCallback): MutableList<Restaurant> 
    var restList : MutableList<Restaurant> = mutableListOf()
    db.collection("restaurant")
        .get()
        .addOnCompleteListener  task ->
            if (task.isSuccessful) 
                restList = updateRestaurantList(task.result!!)
                myCallback.onCallback(restList)
             else 
                Log.w(TAG, "Error getting documents.", task.exception)
            
        
    return restList


private fun updateRestaurantList(restaurants: QuerySnapshot): MutableList<Restaurant> 
    var restList : MutableList<Restaurant> = mutableListOf()
    for (doc in restaurants.documents)
        Log.d(TAG, doc.toString())
        var tempRest : Restaurant? = doc.toObject(Restaurant::class.java)?.withId(doc.id)
        if (tempRest != null) 
            restList.add(tempRest)
        
    
    return restList


/**
 * Class used for the client Binder.  Because we know this service always
 * runs in the same process as its clients, we don't need to deal with IPC.
 */
inner class LocalBinder : Binder() 
    // Return this instance of LocalService so clients can call public methods
    fun getService(): DatabaseManager = this@DatabaseManager


override fun onBind(intent: Intent): IBinder 
    return binder

当我在 onCreate() 方法中手动添加数据时,回收器视图工作正常,但一旦 firebase 完成后不会更新视图,我们将不胜感激。

【问题讨论】:

【参考方案1】:

当我在 onCreate() 方法中手动添加数据但不更新视图时,回收器视图工作正常

这是预期的行为,因为您使用的是 .get() 调用,这基本上意味着您只获取一次数据。您正在寻找的是listening for real-time updates。所以你必须使用addSnapshotListener() 调用。

除此之外,还有一个名为FirebaseUI for android 的有用库,它对Cloud Firestore 有特定用途。

【讨论】:

以上是关于来自 Firebase Firestore 的 Android 反应式列表的主要内容,如果未能解决你的问题,请参考以下文章

使用来自 firebase 实时数据库的 json 数据填充 firestore 数据库

如何将来自不同组件的 firebase auth 和 Cloud Firestore 用作单个 Firebase 应用程序

在 Angular 11 网站上使用 Firestore 和 Firebase 存储进行图像上传功能导致来自 Firebase 的不安全规则通知

Flutter:显示来自经过身份验证的 Firebase Auth 用户的带有 StreamBuilder 的一些 Firestore 集合

在 Flutter 应用程序上过滤和排序 Firebase (Firestore) 数据

如何更新单个 Firebase Firestore 文档