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

如何动态修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 10:48:01