You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法获取Firebase RealtimeDatabase用户列表,RecyclerView无数据如何解决

问题原因与解决方案

核心问题

Firebase Realtime Database的数据查询是异步操作,addListenerForSingleValueEvent绑定的回调不会阻塞当前线程执行。你调用fetchUsers方法时,网络请求还在执行,回调逻辑尚未触发,方法就直接将初始化的空userList返回了。后续回调执行时数据才被写入列表,但此时RecyclerView的适配器已经用空列表完成初始化,没有收到数据更新的通知,所以界面不会显示加载到的用户数据。

解决方案1:回调完成后刷新适配器(无额外依赖)

1. 修改适配器代码

将原来私有的updateList方法改为公开,同时在更新数据后调用notifyDataSetChanged通知RecyclerView刷新:

class UsersAdpater(val context : Context, val gotData : ArrayList<UserInfo>) : RecyclerView.Adapter<UsersAdpater.UserViewHolder>() {

    private var data : ArrayList<UserInfo> = gotData

    // 其他原有代码保持不变

    // 修改为公开方法,增加刷新通知
    fun updateList(userList : ArrayList<UserInfo>) {
        data = userList
        notifyDataSetChanged()
    }

    // 其他原有代码保持不变
}

2. 修改Activity代码

提前初始化适配器,拿到异步返回的用户数据后再调用适配器的更新方法:

class NewMessageActivity : AppCompatActivity() {
    private val TAG = "NewMessageActivityTag/////////////////////////////"
    private lateinit var binding : ActivityNewMessageBinding
    private lateinit var realtimeDatabase : FirebaseDatabase
    // 新增全局适配器、用户列表变量
    private lateinit var usersAdapter: UsersAdpater
    private val userList = ArrayList<UserInfo>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityNewMessageBinding.inflate(layoutInflater)
        setContentView(binding.root)

        supportActionBar?.title = "New Message"
        realtimeDatabase = FirebaseDatabase.getInstance("https://firechat-931d2-default-rtdb.asia-southeast1.firebasedatabase.app/")
        // 提前初始化适配器,传入空列表
        usersAdapter = UsersAdpater(this,userList)
        binding.rvNewMessageActivity.adapter = usersAdapter
        binding.rvNewMessageActivity.layoutManager = LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)
        // 触发数据拉取
        fetchUsers()
    }

    // 修改为无返回值方法,数据加载完成后直接更新适配器
    private fun fetchUsers() {
        val ref = realtimeDatabase.getReference("/users")
        Log.d(TAG,"pidsnigfngadsnfpoin")
        ref.addListenerForSingleValueEvent(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                userList.clear()
                if(snapshot.exists()) {
                    Log.d(TAG,"$snapshot")
                    for(child in snapshot.children){
                        val tempchild = child.getValue(UserInfo::class.java)
                        Log.d(TAG,"$tempchild")
                        userList.add(tempchild ?: UserInfo("default_UID","default_email","default_name","default_picurl"))
                    }
                }
                // 通知适配器刷新数据
                usersAdapter.updateList(userList)
            }

            override fun onCancelled(error: DatabaseError) {
                Log.d(TAG,"$error ${error.message}")
            }
        })
    }
}

解决方案2:协程实现(可选)

如果你偏好协程写法,可以引入Firebase官方Ktx扩展,将回调式API转换为挂起函数:

  1. 先引入依赖:
dependencies {
    implementation 'com.google.firebase:firebase-database-ktx:20.2.2'
}
  1. 修改fetchUsers为挂起函数:
private suspend fun fetchUsers() : ArrayList<UserInfo> {
    val ref = realtimeDatabase.getReference("/users")
    val userList = ArrayList<UserInfo>()
    // 挂起等待请求返回结果
    val snapshot = ref.get().await()
    if(snapshot.exists()) {
        for(child in snapshot.children){
            val tempchild = child.getValue(UserInfo::class.java)
            userList.add(tempchild ?: UserInfo("default_UID","default_email","default_name","default_picurl"))
        }
    }
    return userList
}
  1. 在onCreate中用生命周期协程域调用:
override fun onCreate(savedInstanceState: Bundle?) {
    // 原有初始化逻辑不变
    lifecycleScope.launch {
        val users = fetchUsers()
        usersAdapter.updateList(users)
    }
}

内容的提问来源于stack exchange,提问作者Brahat Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 11:36:04