【问题标题】:Array list in kotlin not storing data after initializationkotlin中的数组列表在初始化后不存储数据
【发布时间】:2020-09-02 16:48:03
【问题描述】:

我正在尝试从 firebase 实时数据库中获取数据,并将其存储在用户数据类列表中以在回收站视图中显示。但该列表不存储任何数据。我尝试在初始化期间添加一些虚拟数据,并且效果很好。但初始化后,它不存储任何东西。 我也尝试过使用可变列表,但这也不起作用。

我正在检索数据的主要片段:

class UserChatFragment : Fragment() {
    lateinit var mobileno: String
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_user_chat, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val session = sessionManager(context!!)
        mobileno = session.getLoginContact()
        val UserList = getusersdata()
        Chat_recyclerview.adapter = UsersAdapter(UserList)
        Chat_recyclerview.layoutManager = LinearLayoutManager(context)
        contact.text = mobileno
    }

    private fun getusersdata(): List<User> {

        val list: = ArrayList<User>()

        val databaseReference =
            FirebaseDatabase.getInstance().reference.child("Users").child("Connections")
                .child(mobileno)
        databaseReference.addListenerForSingleValueEvent(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                if (snapshot.exists()) {
                    for (data: DataSnapshot in snapshot.children) {
                        val userReference = FirebaseDatabase.getInstance().reference.child("Users")
                            .child("Accounts").child(data.key!!)
                        userReference.addListenerForSingleValueEvent(object : ValueEventListener {
                            override fun onDataChange(snapshot: DataSnapshot) {
                                if (snapshot.exists()) {
                                    val item = User(
                                        snapshot.child("name").value.toString(),
                                        snapshot.child("profilePicture").value.toString(),
                                        snapshot.child("phone").value.toString()
                                    )
                                    list.add(item)
                                }
                            }
                            override fun onCancelled(error: DatabaseError) {
                                Toast.makeText(context, error.message, Toast.LENGTH_SHORT).show()
                            }
                        })
                    }
                }
            }
            override fun onCancelled(error: DatabaseError) {
                Toast.makeText(context, error.message, Toast.LENGTH_SHORT).show()
            }
        })
        return list
    }
}

适配器类:


class UsersAdapter(private val userList: List<User>) :
    RecyclerView.Adapter<UsersAdapter.UserViewHolder>() {

    class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val mName: TextView = itemView.cardname
        val mImage: CircleImageView = itemView.cardprofilepicture
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val itemView =
            LayoutInflater.from(parent.context).inflate(R.layout.cardview_chat, parent, false)
        return UserViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        val currentItem = userList[position]

//        Glide.with(UsersAdapter).load()
        Picasso.get().load(currentItem.profileimageurl).into(holder.mImage)
        holder.mName.text = currentItem.name
    }

    override fun getItemCount()=userList.size
}

没有语法错误

【问题讨论】:

  • 而不是ArrayList,尝试使用MutableList。所以它会像:val list: MutableList&lt;User&gt; = mutableListOf()
  • 我试过了,但是效果一样
  • 啊,我明白了,onDataChange 方法是异步工作的,所以不要修改局部变量,你应该修改类属性...。将列表移出到类属性中,然后执行在这些方法中更改它,并且不要忘记将数据更改通知适配器..

标签: android android-studio kotlin


【解决方案1】:

您获取列表getUserList()的方法是异步的;这意味着它需要等待 firebase 产生结果。

您可以看到这一点,因为您执行 databaseReference.addListenerForSingleValueEvent... 意味着您正在添加一个将在未来调用的侦听器,而不是同步调用。

您的方法 (getUserList) 创建一个新列表,并将其返回(空)。

稍后,调用您的 firebase 回调并修改本地列表;已经“太晚了”。

作为“快速破解”,您可以将 getUserList() 方法更改为更像fun fetchResultsAndInitializeAdapter() 的方法(这有点代码味道,因为一个函数正在做“两件事”,但它应该可以工作)。它不返回任何东西。

所以在fetchResultsAndInitializeAdapter 里面你可以在列表填充之后初始化适配器:

                        override fun onDataChange(snapshot: DataSnapshot) {
                            val list: List<xxx>

                            if (snapshot.exists()) {
                                val item = User(
                                    snapshot.child("name").value.toString(),
                                    snapshot.child("profilePicture").value.toString(),
                                    snapshot.child("phone").value.toString()
                                )
                                list.add(item)
                            }

                            adapter = YourAdapter(list)
                            recyclerView.adapter = adapter
                        }

现在,我不会这样做。我相信这个数据库事务和列表突变不属于这里,它属于一个 repo 或一个视图模型,它暴露了你的 Fragment/Activity 观察到的 LiveData,并且当一个值被发出时,它只是被传递到 Adapter .

但在我看来,整个 firebase + 列表创建 + 等不应与 Fragment 的代码混合。

【讨论】:

  • 我将代码更改为 link,但仍然无法正常工作
  • 您正在等待一个回调(该链接中的第 18 行),然后在该 onDataChange 中,您侦听另一个回调(第 24 行)userReference.addListenerForSingleValueEvent。但是您在第 40 行返回了适配器 Chat_recyclerview.adapter = UsersAdapter(list),因此此时列表中没有添加任何内容,因为您需要等待 userReference...您仍然传递一个空列表:)
  • 您需要提供一个存储库(或视图模型)并且您需要订阅并等待这些结果。我没有 Firebase 经验,但这是一个与 Firebase 本身无关的典型问题。这是两个回调的回调嵌套,其中输出由两者定义。对于第一个快照中的每个项目,您必须获取用户,但是您不能迭代每个“连接”,您必须一个接一个地等待用户返回,然后再添加到列表中......
  • 通过添加 adapter.notifyDatasetChanges() 它现在可以正常工作
【解决方案2】:

onDataChange 方法是异步工作的,所以不要修改局部变量,你应该修改类属性....将列表移出到类属性中,并在这些方法中进行更改,不要忘记通知适配器的数据更改..

你需要这样的东西:

class UserChatFragment : Fragment() {
    lateinit var mobileno: String
    val listUser: MutableList<User> = mutableListOf()  // move it out here..


...
... // TLDR
                            // somewhere on your code
                            override fun onDataChange(snapshot: DataSnapshot) {
                                if (snapshot.exists()) {
                                    val item = User(
                                        snapshot.child("name").value.toString(),
                                        snapshot.child("profilePicture").value.toString(),
                                        snapshot.child("phone").value.toString()
                                    )
                                    listUser.add(item)
                                    adapter.notifyDatasetChanges()
                                }
                            }
   ...
}
   

【讨论】:

    猜你喜欢
    • 2010-10-03
    • 2019-10-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2020-02-04
    • 2015-02-17
    • 2017-04-06
    相关资源
    最近更新 更多