【问题标题】:Why is element value added twice when iterating firebase database in Kotlin?为什么在 Kotlin 中迭代 firebase 数据库时元素值添加了两次?
【发布时间】:2018-10-28 13:33:36
【问题描述】:

我正在尝试迭代 firebase-database 并将其元素添加到我的对象中。它有效,但由于某种原因我无法理解,它对每个元素进行两次广告,日志输出显示如下:

TAGZ: DataSnapshot { key = recipeHeaderFirebase, value = Tahini-Oat Cookies } 
TAGZ: DataSnapshot { key = recipeHeaderFirebase, value = Tahini-Oat Cookies }
TAGZ: DataSnapshot { key = recipeHeaderFirebase, value = Chocolate & Cinnamon Cookies }
TAGZ: DataSnapshot { key = recipeHeaderFirebase, value = Chocolate & Cinnamon Cookies }
TAGZ: DataSnapshot { key = recipeHeaderFirebase, value = Sweet Potato Muffin }
TAGZ: DataSnapshot { key = recipeHeaderFirebase, value = Sweet Potato Muffin }
TAGZ: DataSnapshot { key = recipeHeaderFirebase, value = Almond Butter Cookies }
TAGZ: DataSnapshot { key = recipeHeaderFirebase, value = Almond Butter Cookies }

Firebase-database 结构如下所示(注意我暂时忽略了其他元素):

我的 Kotlin 代码如下所示:

fbdb = FirebaseDatabase.getInstance()
ref = fbdb!!.getReference("cookies")

ref!!.addChildEventListener(object: ChildEventListener {

    override fun onChildAdded(snapshot: DataSnapshot?, p1: String?) {
        val children = snapshot!!.children //DIRECT REFERENCE TO CHILD, USED FOR LOOP
        val header = snapshot!!.child("recipeHeaderFirebase")

        for(it in children) {
            var tempRecipe = RecipeTemplate()
            tempRecipe.recipeHeader = header.toString()
            Log.d("TAGZ", tempRecipe.recipeHeader)  //OUTPUT SHOWS DUPLICATE VALUES
            }
        }
    }) 

我错过了什么?我使用类似的代码成功检索了 Xcode 中的元素...

编辑完整的代码请求:

package com.healthandchocolate.sjostedtafzelius.healthchocolateandroid

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.google.firebase.database.*

class RecipeGridView : AppCompatActivity() {

private var fbdb: FirebaseDatabase? = null
private var ref: DatabaseReference? = null
var recipeArray: MutableList<RecipeTemplate> = mutableListOf()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_recipe_grid_view)
    Log.d("TAG", "ON CREATE");

    fbdb = FirebaseDatabase.getInstance()
    ref = fbdb!!.getReference("cookies")

    ref!!.addChildEventListener(object: ChildEventListener {

        override fun onChildChanged(snapshot: DataSnapshot?, p1: String?) {

        }

        override fun onChildMoved(p0: DataSnapshot?, p1: String?) {
            Log.d("TAG", "ON CHILD MOVED");
        }

        override fun onChildRemoved(p0: DataSnapshot?) {
            Log.d("TAG", "ON CHILD REMOVED");

        }

        override fun onCancelled(error: DatabaseError) {
            print(error)
            Log.d("TAG", "ON ERROR");

        }

        override fun onChildAdded(snapshot: DataSnapshot?, p1: String?) {
            Log.d("TAGZ", "CALLED")  //keyName of each child

            val children = snapshot!!.children //DIRECT REFERENCE TO CHILD, USED FOR LOOP
            val header = snapshot!!.child("recipeHeaderFirebase")

            for(it in children) {
                var tempRecipe = RecipeTemplate()
                tempRecipe.recipeHeader = header.toString()
                //Log.d("TAGZ", tempRecipe.recipeHeader)  //keyName of each child

                recipeArray.add(tempRecipe)
            }
        }
        }) //END FB CODE
}
}

【问题讨论】:

  • 事件监听器好像被调用了两次
  • @csblo 有吗?为何如此?在哪里?
  • 你能发布更多你的代码吗?出现错误时您使用什么 IDE?
  • 确实,onChildAdded() 被调用了两次,我的日志显示了。问题是为什么以及如何预防......
  • @csblo 我添加了完整的代码,但实际上并没有更多可显示的内容。使用 Android Studio。

标签: firebase for-loop firebase-realtime-database kotlin duplicates


【解决方案1】:

每次系统将意图路由到当前活动的实例时,都会创建活动。所以函数onCreate可以被多次调用。

每次调用您的函数时,您为addChildEventListener 事件保留的回调函数都会添加到侦听器中。此后,当事件被触发时,回调函数会被调用,就像它之前链接到的监听器一样。

为了防止这种行为,您可以在您的应用清单文件中的标签&lt;activity&gt;中定义android:launchmode:"singleTop"

这允许系统将意图路由到另一个函数 onNewIntent 而不是 onCreate

如需了解更多信息,请浏览: https://developer.android.com/guide/topics/manifest/activity-element#lmode

我希望这会有所帮助。

我尽力写出正确的英文,请随时纠正我。

【讨论】:

    【解决方案2】:

    执行此操作的正确方法是将添加 ChildEventListener 从 onCreate 的代码移动到 onCreate 外部的函数 fun attachValueEventListener()

    然后在 onStart 方法中附加监听器...

    override fun onStart() {
        super.onStart()
        // add an event listener to watch changes in firebase database
        attachValueEventListener()
    }
    

    ...并在 onStop 中分离监听器

    override fun onStop() {
        super.onStop()
        // detach the event listener that watches changes in firebase database
        detachValueEventListener()
    }
    
    private fun detachValueEventListener() {
        if (mValueEventListener != null) {
            myRef?.removeEventListener(mValueEventListener)
            mValueEventListener = null
        }
    }
    

    您还需要声明

    private var mValueEventListener: ValueEventListener? = null
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-28
      • 1970-01-01
      • 1970-01-01
      • 2018-06-29
      • 2021-12-02
      • 1970-01-01
      • 2013-07-20
      相关资源
      最近更新 更多