如何动态修改ViewModel属性实现Room DAO动态查询获取正确数据
解决方案
核心思路是用Transformations.switchMap将动态变化的时间范围封装为可观察对象,每当时间参数更新时自动触发Room重新查询,生成新的LiveData并回调给观察者。
第一步:修改ViewModel代码
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel class GraphViewModel( dataSource: NetWalletDatabaseDao, application: Application, email: String, walletType: String ) : ViewModel() { private val database = dataSource // 封装时间范围为可观察对象,初始值可设置为0到0 private val _dateRange = MutableLiveData<Pair<Long, Long>>() // 时间范围变化时自动触发收入数据重新查询 val lastSevenDaysIncome: LiveData<List<IncomeTransaction>> = Transformations.switchMap(_dateRange) { range -> database.getLastSevenIncomeTransaction(walletType, email, range.first, range.second) } // 时间范围变化时自动触发支出数据重新查询 val lastSevenDaysExpenses: LiveData<List<ExpensesTransaction>?> = Transformations.switchMap(_dateRange) { range -> database.getLastSevenDaysExpensesTransaction(walletType, email, range.first, range.second) } fun updateDateRange(fromParam: Long, toParam: Long) { // 更新时间范围即可自动触发重新查询 _dateRange.value = fromParam to toParam } }
第二步:修改Fragment代码
修复原有重复观察、数据累加的问题,调整观察逻辑:
val application = requireNotNull(this.activity).application val dataSource = NetWalletDatabase.getInstance(application).netWalletDatabaseDao val viewModelFactory = GraphViewModelFactory( dataSource, application, getEmail.toString(), getWalletType.toString(), ) val viewModel = ViewModelProvider(this, viewModelFactory).get(GraphViewModel::class.java) val tvLastSevenDays = binding.tvLastSevenDays // 传入时间范围触发首次查询 viewModel.updateDateRange(sevenDaysInMili, todayMili) val chart : LineChart = binding.chart // 合并观察收入和支出数据 viewModel.lastSevenDaysExpenses.observe(viewLifecycleOwner) { expensesList -> viewModel.lastSevenDaysIncome.observe(viewLifecycleOwner) { incomeList -> // 每次更新先清空集合,避免旧数据累加 val expenses = ArrayList<Entry>() val income = ArrayList<Entry>() expensesList?.forEachIndexed { index, item -> expenses.add(Entry(index.toFloat(), item.value!!.toFloat())) } incomeList?.forEachIndexed { index, item -> income.add(Entry(index.toFloat(), item.value!!.toFloat())) } // 构造支出数据集 val expensesLineDataSet = LineDataSet(expenses, "Expenses").apply { mode = LineDataSet.Mode.CUBIC_BEZIER color = Color.BLUE circleRadius = 5f setCircleColor(Color.BLUE) } // 构造收入数据集 val incomeLineDataSet = LineDataSet(income, "Income").apply { mode = LineDataSet.Mode.CUBIC_BEZIER color = Color.RED circleRadius = 5f setCircleColor(Color.RED) } // 图表通用配置 val legend = chart.legend.apply { isEnabled = true verticalAlignment = Legend.LegendVerticalAlignment.TOP horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER orientation = Legend.LegendOrientation.HORIZONTAL setDrawInside(false) } chart.apply { description.isEnabled = false xAxis.position = XAxis.XAxisPosition.BOTTOM data = LineData(expensesLineDataSet, incomeLineDataSet) animateXY(100, 500) } } }
其他说明
- 原有DAO代码无需修改
- 后续需要切换其他时间范围时,仅需调用
viewModel.updateDateRange(新起始时间, 新结束时间)即可自动触发查询和UI刷新 - 若使用AndroidX Lifecycle 2.2.0及以上版本,也可以用
liveData协程构建器替代Transformations.switchMap,实现逻辑本质一致
内容的提问来源于stack exchange,提问作者Jugs
相关产品推荐
相关产品推荐

