0

我的项目是一个费用跟踪器,我在其中显示一个日期列表,在该列表下我有一个在这些日期发生的费用列表。我嵌套了 RecyclerViews。父 RecyclerView 是所有费用的唯一日期列表。Child RecyclerView 是费用列表(当然,在唯一日期下查看)。我的 ViewModel 有一个 ExpenseEntity 的 LiveData 列表。ViewModel 必须有一个包含唯一日期的 LiveData 列表。我从 Room 数据库中获取了我的 ExpenseEntity 列表。

我的主要片段观察了 ExpenseEntities 的 LiveData,因为那时我需要更新我的父子回收器视图。

我无法弄清楚如何使用 Transformations.map 来获得唯一日期的实时转换列表。一旦更新了 ExpenseEntity 的 LiveData,我应该如何确保始终更新 Dates 的 LiveData?

MainActivityViewModel.kt

class MainActivityViewModel(private val expenseDao: ExpenseDao) : ViewModel() {
    val allExpenses : LiveData<List<ExpenseEntity>> = expenseDao.fetchAllExpenses().asLiveData()
    val uniqueDates : LiveData<List<Date>> = Transformations.map(allExpenses) {
        it.map { expense ->
            expense.date!!
        }.distinct()
    }
...
}

费用片段.kt

val factory = MainActivityViewModelFactory((activity?.application as SimpleExpenseTrackerApp).db.expenseDao())
expensesViewModel = ViewModelProvider(this, factory).get(MainActivityViewModel::class.java)


binding.rvParentExpenseDates.layoutManager = LinearLayoutManager(requireContext())
expensesViewModel.allExpenses.observe(viewLifecycleOwner){ expensesList ->
    if (expensesList.isNotEmpty()){
       binding.rvParentExpenseDates.adapter = expensesViewModel.uniqueDates.value?.let {
           ParentDatesAdapter(it, expensesList) { expenseId ->
               Toast.makeText(requireContext(), "Clicked expense with id: $expenseId", Toast.LENGTH_LONG).show()
                }
            }
       binding.rvParentExpenseDates.visibility = View.VISIBLE
    } else {
       binding.rvParentExpenseDates.visibility = View.GONE
    }
}

费用实体.kt

@Entity(tableName = "expense-table")
data class ExpenseEntity(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    @ColumnInfo(name = "date-time")
    val dateTime : Date?,
    val date : Date?,
    @ColumnInfo(name = "account-type")
    val accountType : String = "",
    val category : String = "",
    val amount : Double = 0.0,
    val currency : String = "",
    val note : String = ""

)

4

1 回答 1

1

根据文档

这些方法允许 LiveData 实例的功能组合和委托。转换是惰性计算的,只有在观察到返回的 LiveData 时才会运行。生命周期行为从输入源 LiveData 传播到返回的源。

这里的问题是您永远不会观察到转换后的LiveData( uniqueDates) - 您只检查value,因此永远不会应用转换。

如果您同时需要两者,一个选项是映射到连接视图:

class MainActivityViewModel(private val expenseDao: ExpenseDao) : ViewModel() {
  val allExpenses : LiveData<List<ExpenseEntity>> =
    expenseDao.fetchAllExpenses().asLiveData()

  val allAndUniqueDatedExpenses: LiveData<Pair<List<ExpenseEntity>, List<Date>> = 
    Transformations.map(allExpenses) { expenses ->
      expenses to expenses.mapNotNull { it.date }.distinct()
    }
}

然后简单地观察这个联合值:

expensesViewModel.allAndUniqueDatedExpenses.observe(this) { (expenses, dates) ->
  binding.rvParentExpenseDates.adapter = 
    ParentDatesAdapter(dates, expenses) { expenseId ->
      Toast.makeText(...).show()
    }
}

但是,我会在这里争辩说,您实际上并不需要其他LiveData转换。只需进行内联转换:

expensesViewModel.allExpenses.observe(this) { expenses ->
  val dates = expenses.mapNotNull { it.date }.distinct()

  binding.rvParentExpenseDates.adapter =
    ParentDatesAdapter(dates, expenses) { expenseId ->
      Toast.makeText(...).show()
    }
}
于 2022-02-19T04:14:03.050 回答