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

使用MVVM架构跳转其他Fragment后返回时RecyclerView列表重复问题

RecyclerView列表重复问题修复方案

根因

  • 全局列表未清空:ViewModel中持有的arrayListMainUI不会随Fragment销毁而清空,每次加载数据时直接向列表追加新数据,导致旧数据重复累加
  • 重复注册Firebase监听器:每次返回Fragment都会执行loadData(true),重复添加ValueEventListener,同一份数据会触发多次回调,多次插入列表
  • ViewModel生命周期绑定问题:使用requireActivity()初始化ViewModel,ViewModel生命周期和Activity一致,Fragment销毁时ViewModel内的数据、监听器都会保留,返回后重复执行逻辑进一步放大重复问题

修复步骤

1. 修改ViewModel代码

private var listMutableLiveData: MutableLiveData<ArrayList<OffersModelClass>> = MutableLiveData()
var arrayListMainUI: ArrayList<OffersModelClass> = ArrayList()
val listLiveData: LiveData<ArrayList<OffersModelClass>> get() = listMutableLiveData
// 新增:保存监听器引用,避免重复注册
private var valueEventListener: ValueEventListener? = null

fun loadData(reload: Boolean) {
    if (reload && valueEventListener == null) { // 仅未注册监听器时才添加
        valueEventListener = object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                // 新增:加载数据前先清空旧列表,避免累加
                arrayListMainUI.clear()
                val tempList = ArrayList<OffersModelClass>()
                for (data in snapshot.children) {
                    val model = data.getValue(OffersModelClass::class.java) ?: continue
                    val imageID: String = model.imageID.toString()
                    val fileRef11 = FirebaseStorage.getInstance().reference.child("offers/$imageID.jpg")
                    fileRef11.downloadUrl.addOnSuccessListener { uri ->
                        model.ImageUri = uri.toString()
                        model.Time = model.Time?.let { calculateTimeAge(it) }
                        tempList.add(model)
                        // 所有数据加载完成后再更新列表,避免频繁刷新
                        if (tempList.size == snapshot.childrenCount.toInt()) {
                            arrayListMainUI.addAll(tempList)
                            listMutableLiveData.postValue(arrayListMainUI)
                        }
                    }
                }
            }
            override fun onCancelled(error: DatabaseError) {
                TODO("Not yet implemented")
            }
        }
        databaseReference.addValueEventListener(valueEventListener!!)
    }
}

// 新增:页面销毁时移除监听器,避免内存泄漏
fun removeListener() {
    valueEventListener?.let {
        databaseReference.removeEventListener(it)
        valueEventListener = null
    }
}

2. 修改Fragment代码

recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.setHasFixedSize(true)
// 初始化一次Adapter即可,不要每次数据更新都新建
offerAdapter = OfferAdapter(ArrayList())
recyclerView.adapter = offerAdapter

viewModel = ViewModelProvider(requireActivity()).get(ViewModel::class.java) 

if (user != null && viewModel.listLiveData.value == null) { // 仅首次无数据时加载,避免重复请求
    viewModel.loadData(true)
}
viewModel.listLiveData.observe(viewLifecycleOwner, { arrayList ->
    // 直接更新Adapter数据即可,也可给Adapter自定义updateData方法提升性能
    offerAdapter = OfferAdapter(arrayList)
    recyclerView.adapter = offerAdapter
})

// 新增:Fragment销毁时通知ViewModel移除监听器
override fun onDestroyView() {
    super.onDestroyView()
    viewModel.removeListener()
}

可选优化

如果不需要实时监听Firebase数据变化,直接把addValueEventListener换成addListenerForSingleValueEvent,请求完成后监听器会自动销毁,不需要手动管理,更适合静态列表场景。

内容的提问来源于stack exchange,提问作者Mohammad Mawed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 08:48:03