You need to enable JavaScript to run this app. Android Kotlin 接入Firestore后返回Fragment操作ListView空指针崩溃
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin 接入Firestore后返回Fragment操作ListView空指针崩溃

崩溃根本原因
  • 你注册的Firestore实时快照监听器没有绑定Fragment生命周期,Fragment退栈销毁View后,监听器仍然存活,触发回调时尝试访问已经被回收的listView控件,直接引发空指针异常
  • startingTheGame()方法每次被调用都会重复给按钮、ListView设置点击事件,同时重复注册快照监听器,多次回调叠加会进一步加剧空指针风险
  • 全局roomsList没有在Fragment退出时清空,重新进入后旧数据残留,也会引发列表展示异常
  • 原代码在快照回调的循环中重复设置ListView Adapter,属于冗余操作,会额外增加异常概率
具体修复方案

1. 给快照监听器增加生命周期管理

首先在Fragment中声明监听器引用变量,在View销毁时主动取消监听,避免内存泄漏和无效回调:

class SeviyeBirFragment : Fragment() {
    // 原有变量声明
    private var roomListenerRegistration: ListenerRegistration? = null
    private var roomsListListenerRegistration: ListenerRegistration? = null

    // 原有逻辑

    override fun onDestroyView() {
        super.onDestroyView()
        // View销毁时取消所有Firebase监听
        roomListenerRegistration?.remove()
        roomsListListenerRegistration?.remove()
        roomListenerRegistration = null
        roomsListListenerRegistration = null
    }
}

注册监听器时接收返回的注册对象:

// roomListener方法中修改
roomListenerRegistration = db.collection("Rooms").addSnapshotListener { value, error ->
    // 原有逻辑
}

// addRoomsEventListener方法中修改
roomsListListenerRegistration = db2.collection("Rooms").addSnapshotListener { value, error ->
    // 原有逻辑
}

2. 调整点击事件注册位置,避免重复绑定

把createRoomButton的点击事件、listView的条目点击事件从startingTheGame()方法移动到onViewCreated中,只在Fragment第一次创建View时注册一次即可。

3. 列表数据与UI更新优化

优先在注册监听器时传入viewLifecycleOwner,让Firebase自动绑定Fragment生命周期,只有Fragment处于活跃状态时才会触发回调,同时优化列表更新逻辑:

private fun addRoomsEventListener() {
    // 传入viewLifecycleOwner,View销毁后自动停止回调
    roomsListListenerRegistration = db2.collection("Rooms").addSnapshotListener(viewLifecycleOwner) { value, error ->
        if (error != null) return@addSnapshotListener
        value ?: return@addSnapshotListener

        roomsList.clear() // 先清空旧数据,避免重复叠加
        val documents = value.documents
        for (document in documents) {
            val deger = document.getString("player1")
            val deger2 = document.getString("player2")
            deger?.let { roomsList.add(it) }
            deger2?.let { roomsList.add(it) }
        }
        // 所有数据遍历完成后只更新一次adapter,加空安全调用避免空指针
        val arrayAdapter = context?.let { ArrayAdapter(it, android.R.layout.simple_list_item_1, roomsList) }
        listView?.adapter = arrayAdapter
    }
}

4. 额外优化点

  • FirebaseFirestore实例不需要初始化两个,全局复用一个即可
  • 加入房间时player2的写入逻辑有问题,不要调用add()方法新建文档,应该找到对应房间的文档调用update()方法更新字段,否则会生成无效的重复房间数据

内容的提问来源于stack exchange,提问作者Rüçhan Okal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 00:27:04