【问题标题】:MutableList remaining empty (?) even though i'm populating it即使我正在填充 MutableList 仍然为空(?)
【发布时间】:2021-11-25 01:34:45
【问题描述】:

我正在尝试填充一个可变列表,以便可以将其用于回收站视图。不幸的是,虽然(我认为)我正在填充列表,但它仍然是空的,并且回收器视图不起作用(我想这是因为列表问题)。代码见下:

        private val newList: MutableList<NewListModel> = mutableListOf()
        private val oldList = retrieveOldList()

        private fun retrieveAndPopulate() {
                
                for (i in 0 until oldList.size){
        
                    val oldItem = oldList[i]
                    
                    val itemOne = oldItem.itemOne
                    val itemTwo = oldItem.itemTwo
                    val itemThree = oldItem.itemThree
                    val itemFour = oldItem.itemFour
    
                    val newItemData =
                        NewListModel(
                            itemOne, itemTwo, itemThree, itemFour
                        )
    
                newList.add(newItemData)
                Log.d(
                    "RetrieveData",
                    "${newItemData.itemOne} has been added to the list."
                )
            }
        }

下面的类是针对“NewListModel”的

@Keep
@IgnoreExtraProperties
data class NewListModel (
    var itemOne: String ?= null,
    var itemTwo: String ?= null,
    var itemThree: String ?= null,
    var itemFour: String ?= null,
)

下面是我如何尝试填充“oldList”

fun retrieveData(): MutableList<OldListModel> {

        val list: MutableList<OldListModel> = mutableListOf()
        val ref = FirebaseDatabase.getInstance().getReference("/storage")

        ref.addValueEventListener(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                if (snapshot.exists()) {
                    ref.get()
                        .addOnSuccessListener {

                            for (listItem in snapshot.children) {
                                val listItem = snapshot.getValue(OldListModel::class.java)

                                if (listItem != null) {
                                    list.add(listItem)
                                }
                            }
                        }
                } else {
                    Log.d(
                        "Data",
                        "Retrieving data was unsuccessful."
                    )
                }
            }

            override fun onCancelled(error: DatabaseError) {
            }
        })
        return list
}

值得一提的是,我从一个可变列表中获取数据并将其添加到另一个列表中。非常感谢任何帮助

(以下是我如何尝试填充回收站视图)

val newList = retrieveAndPopulate()

val recyclerView = findViewById<View>(R.id.recyclerView) as RecyclerView
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
val adapterAdapter = AdapterAdapter(newList)
recyclerView.adapter = adapterAdapter

【问题讨论】:

  • 您在一个无效的函数中声明了两个 private 字段 - 您的代码甚至不应该编译。您确定旧列表中有项目吗? newList 会发生什么?你真的把它喂给适配器了吗?请展示一个完整的工作示例。
  • @dominicoder 那是我的错,我把它粘贴到了错误的地方。是的,我确定 oldList 已填充,因为当我使用“Log.d”打印它的内容时,我实际上得到了一个包含内容的可变列表。 newList 甚至什么都不做。该消息甚至没有被打印出来。 RE 回收站视图,我将其提供给适配器
  • @dominicoder 如果有帮助,我已经添加了我用来填充回收站视图的代码的 sn-p。
  • val newList = retrieveAndPopulate() 无效,因为您永远不会从retrieveAndPopulate() 返回任何内容。如果消息没有被打印,那么你的旧列表是空的。调试您的应用以确定故障点:developer.android.com/studio/debug
  • @dominicoder 你是对的,我试图调试代码并意识到 oldList 实际上并没有被填充(我以为是,但我意识到我只是在打印快照,这给了它工作的印象)。我添加了填充 oldList 的代码 sn-p。你知道什么可能导致这个问题吗? - 非常感谢到目前为止的帮助!

标签: android kotlin mutablelist


【解决方案1】:

你的问题是你认为你在异步运行代码时是按顺序运行的。查看函数中编号的 cmets 以跟踪执行顺序:

fun retrieveData(): MutableList<OldListModel> {

    // 1. Here you create a list
    val list: MutableList<OldListModel> = mutableListOf()
    val ref = FirebaseDatabase.getInstance().getReference("/storage")

    // 2. Here a listener is added that will let you know LATER when the data is ready
    ref.addValueEventListener(object : ValueEventListener {
        // 4. LATER the data changed will get called
        override fun onDataChange(snapshot: DataSnapshot) {
            if (snapshot.exists()) {
                ref.get()
                    .addOnSuccessListener {
                        // 5. EVEN LATER this listener is called with data
                        for (listItem in snapshot.children) {
                            val listItem = snapshot.getValue(OldListModel::class.java)

                            // 6. FINALLY - you add to a list that has long since stopped being relevant
                            if (listItem != null) {
                                list.add(listItem)
                            }
                        }
                    }
            } else {
                Log.d(
                    "Data",
                    "Retrieving data was unsuccessful."
                )
            }
        }

        override fun onCancelled(error: DatabaseError) {
        }
    })
    return list // 3. Here you return the EMPTY list that was created
}

一个解决方案——虽然可能不是最好的解决方案是在回调完成后更新您的列表:

private val theList = mutableListOf<YourDataModelType>

fun retrieveData(): { // No longer returning anything

    // Remove this, no longer returning anything
    // val list: MutableList<OldListModel> = mutableListOf()

    val ref = FirebaseDatabase.getInstance().getReference("/storage")
    ref.addValueEventListener(object : ValueEventListener {
        override fun onDataChange(snapshot: DataSnapshot) {
            if (snapshot.exists()) {
                ref.get()
                    .addOnSuccessListener {
                        theList.clear() // Clear out existing data

                        for (listItem in snapshot.children) {
                            val listItem = snapshot.getValue(OldListModel::class.java)

                            if (listItem != null) {
                                theList.add(listItem)
                            }
                        }
                        
                        // Since you're using Kotlin, you could use a map,
                        // but that's unrelated to this issue
                        // val list = snapshot.children.map { getValue(...) }.filterNotNull()
                        
                        // Now that we have a full list here, update:
                        updateAdapterWithNewData(theList)
                    }
            } else {
                Log.d(
                    "Data",
                    "Retrieving data was unsuccessful."
                )
            }
        }

        override fun onCancelled(error: DatabaseError) {
        }
    })
}

updateAdapterWithNewData 是一个你写的函数,按照它说的去做。

请阅读异步编程,并确保您了解在 Firebase 等框架中使用回调/侦听器时代码是如何流动的。

【讨论】:

  • 感谢您的帮助,这解决了问题,但是如果我从“retrieveData”方法中删除返回值,我该如何从另一个类访问数据呢?理想情况下,我希望能够从类中的任何位置(全局变量)访问列表,但我正在努力做到这一点,因为“retrieveData”方法(现在)不返回任何内容并且存储列表的变量在上述方法中本地化。
  • 然后不要在所述方法中本地化它 - 改用类字段。查看更新。
  • 我遵循了这个例子,虽然旧的列表被填充(肯定),但新的列表没有更新。每次我从方法内部访问变量时,我都会返回正确的值,但是一旦我尝试从方法外部访问它,列表就是空的。我不知道为什么
  • 可能出于与原始问题完全相同的原因 - 您在填充数据之前访问数据。当然,我只能猜测,没有任何代码可以看。
  • 我遵循了这个例子link。第一个答案似乎解决了我遇到的问题,我的问题已经解决。感谢您帮助我指明了正确的方向。
【解决方案2】:

我遇到的问题是在尝试访问 onSuccessListener 中的数据时未使用 callbacks。这导致列表根本没有更新。

在网上翻了一天,终于找到了以下解决方案:

  1. 解决方案:link

  2. 解决方案的扩展:link

这解决了我的问题,我希望它也能解决你的问题!

【讨论】:

    猜你喜欢
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 2014-08-03
    • 1970-01-01
    • 2012-12-03
    • 2015-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多