Android Fragment内ArrayList自动重复扩容,Intent传参时大小异常
问题原因
- 核心问题为可变集合引用共享:Firestore回调返回的
list是可变集合实例,你先后将该实例传给DealsAdapter、赋值给全局变量deals,三者持有同一个集合的引用。若任意一处修改了该集合(比如DealsAdapter为实现无限轮播效果首尾追加重复项、内部逻辑插入元素),全局deals的内容也会同步被修改,大小不断累加。 - 叠加调用时机问题:
getDeals方法大概率在Fragment生命周期中被多次触发(比如onResume每次可见都调用、onCreateView每次重建视图都调用),每次回调拿到的集合已经被之前的逻辑修改过,赋值给deals后大小就会持续增长。 - 隐藏放大问题:你在
successDeals中每次调用都重复给ViewPager2注册OnPageChangeCallback、重复创建Handler和Runnable,从未做移除操作,既会导致内存泄漏,也会多次触发轮播逻辑,进一步提升集合被修改的概率。
解决方案
1. 切断集合引用共享,每次使用都做独立拷贝
修改getDeals的成功回调逻辑,不要直接使用Firestore返回的list引用,每次都创建新的ArrayList拷贝内容,避免不同组件共享同一个集合,同时删除无意义的deals.clear()代码:
private fun getDeals() { FirestoreClass().getDeals( onSuccess = { list -> Result.success(list) // 给successDeals传独立拷贝的集合 successDeals(ArrayList(list)) // 全局deals也用独立拷贝,不要直接赋值引用 deals = ArrayList(list) Log.d("Tag1", "Size is ${deals.size}") }, onFailure = { } ) }
2. 避免重复调用和重复注册监听
- 把
getDeals的调用放到onCreate中,而非onCreateView/onResume,保证Fragment生命周期内仅调用一次,确有刷新需求再主动触发。 - 修改
successDeals逻辑,每次注册回调前先移除旧回调,同时在Fragment销毁视图时清理资源:
private fun successDeals(list: ArrayList<Deals>) { Log.d("Tag3", "Size is ${deals.size}") if (list.size > 0) { binding.vpDeals.visibility = View.VISIBLE // 先移除旧的页面变化回调 binding.vpDeals.clearOnPageChangeCallbacks() val adapter = DealsAdapter(binding.vpDeals,requireContext(), list) binding.vpDeals.adapter = adapter binding.vpDeals.orientation = ViewPager2.ORIENTATION_HORIZONTAL // 先移除之前的Handler任务 sliderHandle.removeCallbacks(sliderRun) sliderRun= Runnable { binding.vpDeals.currentItem=binding.vpDeals.currentItem+1 } binding.vpDeals.registerOnPageChangeCallback( object :ViewPager2.OnPageChangeCallback(){ override fun onPageSelected(position: Int) { super.onPageSelected(position) sliderHandle.removeCallbacks(sliderRun) sliderHandle.postDelayed(sliderRun,4000) } } ) } else { binding.vpDeals.visibility = View.GONE } } // 补充生命周期资源清理逻辑 override fun onDestroyView() { sliderHandle.removeCallbacks(sliderRun) binding.vpDeals.clearOnPageChangeCallbacks() super.onDestroyView() }
3. 可选语法防护
若要从根源避免集合被意外修改,可以把deals声明为只读列表:
// 替换原来的可变列表声明 private var deals: List<Deals> = emptyList()
后续修改必须重新赋值整个列表,从语法层面禁止集合内容被局部逻辑意外修改。
内容的提问来源于stack exchange,提问作者Codist
相关产品推荐
相关产品推荐

