如何用协程在后台线程过滤ArrayList?Adapter无法观察LiveData求助
解决方案:将LiveData观察逻辑移至Fragment,而非Adapter
Adapter的核心职责是绑定数据到视图,它不应该持有LiveData的观察逻辑——这会导致生命周期不匹配(Adapter没有LifecycleOwner),进而引发内存泄漏或UI异常。正确的做法是把LiveData的观察放在Fragment中,再将过滤后的结果传递给子Adapter。
步骤1:修正ViewModel的LiveData命名与逻辑
先规范ViewModel中LiveData的命名(下划线开头对应私有MutableLiveData,对外暴露不可变的LiveData),并确保过滤后的数据正确转为MutableList:
class MainFragmentViewModel : ViewModel() { // 私有可变LiveData,仅内部更新 private val _filterGoldList = MutableLiveData<MutableList<Item>>() // 对外暴露不可变的LiveData val filterGoldList: LiveData<MutableList<Item>> = _filterGoldList private val _filterSilverList = MutableLiveData<MutableList<Item>>() val filterSilverList: LiveData<MutableList<Item>> = _filterSilverList suspend fun myFilter(myList: MutableList<Item>, type: String) = withContext(Dispatchers.IO) { // 执行后台过滤,转为MutableList val filteredList = myList.filter { it.isMainPageItem == true }.toMutableList() // 根据类型更新对应LiveData when(type.lowercase()) { "gold" -> _filterGoldList.postValue(filteredList) "silver" -> _filterSilverList.postValue(filteredList) } } }
步骤2:在Fragment中观察LiveData并管理子Adapter
在Fragment中持有子Adapter的引用,通过viewLifecycleOwner安全观察LiveData,数据变化时直接更新子Adapter:
class MainFragment : Fragment() { private lateinit var mainFragmentViewModel: MainFragmentViewModel // 持有子Adapter引用,避免重复创建 private lateinit var goldAdapter: GoldAdapter private lateinit var silverAdapter: SilverAdapter override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) mainFragmentViewModel = ViewModelProvider(this)[MainFragmentViewModel::class.java] // 初始化子Adapter goldAdapter = GoldAdapter() silverAdapter = SilverAdapter() // 初始化主Adapter,传入子Adapter引用 val mainAdapter = MainFragmentAdapter(goldAdapter, silverAdapter, mRate, requireContext()) mainRecyclerView.adapter = mainAdapter // 观察黄金过滤列表 mainFragmentViewModel.filterGoldList.observe(viewLifecycleOwner) { filteredGold -> if (filteredGold.isNotEmpty()) { goldAdapter.goldList = filteredGold goldAdapter.notifyDataSetChanged() } } // 观察白银过滤列表(同理) mainFragmentViewModel.filterSilverList.observe(viewLifecycleOwner) { filteredSilver -> if (filteredSilver.isNotEmpty()) { silverAdapter.silverList = filteredSilver silverAdapter.notifyDataSetChanged() } } // 触发后台过滤 mainFragmentViewModel.viewModelScope.launch { mainFragmentViewModel.myFilter(parentGoldList, "gold") mainFragmentViewModel.myFilter(parentSilverList, "silver") } } }
步骤3:重构主Adapter,复用子Adapter实例
修改主Adapter的构造函数,传入已初始化的子Adapter,避免在onBindViewHolder中重复创建:
class MainFragmentAdapter( private val goldAdapter: GoldAdapter, private val silverAdapter: SilverAdapter, private val mRate: List<Rate>, private val myContext: Context ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (position) { 1 -> { holder.itemView.diamond_text.text = "Gold" // 复用已有的goldAdapter holder.itemView.diamond_recycler.apply { setHasFixedSize(true) adapter = goldAdapter } // 设置费率数据 if (mRate.isNotEmpty()) { goldAdapter.goldRate = mRate[0].value!! } holder.itemView.view_more_button.setOnClickListener { methodCallBack.click(gold) } goldAdapter.setListener(myContext) } // 处理白银类型的item(同理复用silverAdapter) 2 -> { // ... } } } // 其他必要方法(getItemCount、onCreateViewHolder等) }
核心逻辑说明
- 职责分离:Fragment负责数据观察与Adapter管理,Adapter仅做数据-视图绑定,符合单一职责原则。
- 生命周期安全:使用
viewLifecycleOwner观察LiveData,确保Fragment销毁时自动取消观察,避免内存泄漏。 - 性能优化:复用子Adapter实例,避免在
onBindViewHolder中重复创建对象,减少性能开销。
内容的提问来源于stack exchange,提问作者Mattwalk
相关产品推荐
相关产品推荐

