基于Spinner选中项过滤关联Spinner的ViewModel LiveData数据(MVVM)
符合MVVM规范的双Spinner联动实现方案
核心思路
用Jetpack Lifecycle组件提供的Transformations.switchMap实现响应式过滤,仅需在ViewModel中新增一个选中项的LiveData作为过滤触发源,过滤逻辑全在ViewModel侧完成,Fragment完全不持有业务数据,也无需手动维护过滤后的列表。
ViewModel 代码修改
// 原有全量数据LiveData无需修改 val allAppDataProductGroups: LiveData<ArrayList<ProductGroupObject>> = ... val allAppDataProductTypes: LiveData<ArrayList<ProductTypeObject>> = ... // 新增:存储当前选中的产品组 val selectedProductGroup = MutableLiveData<String?>() // 新增:自动响应过滤的产品类型列表 val filteredProductTypes = Transformations.switchMap(selectedProductGroup) { group -> Transformations.map(allAppDataProductTypes) { allTypes -> when { group.isNullOrEmpty() -> allTypes else -> ArrayList(allTypes.filter { it.productGroup == group }) } } } // 供Fragment调用更新选中的产品组 fun updateSelectedGroup(groupName: String) { // 重复选中不触发过滤,减少无用计算 if (selectedProductGroup.value != groupName) { selectedProductGroup.value = groupName } }
Fragment 代码修改
// 产品组Spinner观察者,新增选中监听 businessViewModel.allAppDataProductGroups.observe(viewLifecycleOwner, { productGroupArrayList -> if (!productGroupArrayList.isNullOrEmpty()){ val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, productGroupArrayList) binding.inventoryAddEditProductGroupSpinner.adapter = adapter // 绑定选中事件 binding.inventoryAddEditProductGroupSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { val selectedGroup = parent?.getItemAtPosition(position) as ProductGroupObject businessViewModel.updateSelectedGroup(selectedGroup.productGroup) } override fun onNothingSelected(parent: AdapterView<*>?) { businessViewModel.updateSelectedGroup("") } } } }) // 替换原有的全量产品类型观察者,改为观察过滤后的列表 businessViewModel.filteredProductTypes.observe(viewLifecycleOwner, { filteredTypeList -> if (!filteredTypeList.isNullOrEmpty()){ val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, filteredTypeList) binding.inventoryAddEditProductTypeSpinner.adapter = adapter // 自适应默认选中位置,避免索引越界 val defaultPos = if (filteredTypeList.size > 17) 17 else 0 binding.inventoryAddEditProductTypeSpinner.setSelection(defaultPos) } })
方案优势
- 完全符合MVVM规范:Fragment仅做视图交互,无业务数据持有,过滤逻辑全在ViewModel中实现,可单独单元测试
- 无冗余代码:不需要频繁注销/注册观察者,全量数据更新、选中项变更时都会自动触发重新过滤
- 内存占用极低:过滤后的列表为临时计算生成,无需手动维护持久化存储,旧列表会被自动GC回收,不会增加冗余内存占用
内容的提问来源于stack exchange,提问作者Scamparelli
相关产品推荐
相关产品推荐

