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
相关产品推荐
相关产品推荐

