将两个 LiveData<Int> 合并为一个 LiveData<List<Pair<Int, Int>>>

Combine two LiveData<Int> into one LiveData<List<Pair<Int, Int>>>

我想显示一个点阵图,其中点的 x 坐标为消耗的卡路里,y 坐标为燃烧的卡路里。我在我的 ViewModel 中检索了两个卡路里,但我想将它们组合成一个 LiveData<List<Pair<Int, Int>>>。这样我就可以在我的片段中观察这个 LiveData 并访问具有 x 和 y 坐标(卡路里)的 Pairs 列表。

这是我的 DAO,我有两个类型为 List<Int>:

的 liveData
@Query("SELECT amount from calories_table WHERE strftime('%m-%d-%Y', timestamp, 'unixepoch') IN (SELECT strftime('%m-%d-%Y', timestamp, 'unixepoch') FROM running_table)")
fun getCaloriesConsumedOnRunDays(): LiveData<List<Int>>

@Query("SELECT caloriesBurned FROM running_table")
fun getCaloriesFromRuns():LiveData<List<Int>>

这是我的存储库:

fun getCaloriesConsumedOnRunDays() = runDao.getCaloriesConsumedOnRunDays()

fun getCaloriesFromRuns() = runDao.getCaloriesFromRuns()

最后,我在存储两个 liveData 的 ViewModel 中创建了这两个变量:

private val getCaloriesConsumedOnRunDays = mainRepository.getCaloriesConsumedOnRunDays()

private val getCaloriesFromRuns = mainRepository.getCaloriesFromRuns()

首先,这是您的第一个问题,欢迎。

有两种方法可以解决您要执行的操作。

  1. 这特定于您要尝试执行的操作...我建议仅在单个 SQLite 查询调用中提取所有数据,这将是更有效的方法。 SQLite 以 C 级速度运行,您宁愿让它完成所有繁重的工作,而不是在 VM 上使用 Kotlin 执行粘合代码。 (此外,将避免使用子select,另外,如果您只是在做WHERE .. IN;那么就没有理由在它们周围做strftime,因为您只是想做直接匹配)。

这可能与您的想法背道而驰,但像这样:

@Query("""
SELECT calories_table.amount, running_table.caloriesBurned 
FROM calories_table 
INNER JOIN running_table ON calories_table.timestamp = running_table.timestamp")
"""
fun getCaloriesConsumedOnRunDays(): LiveData<List<Pair<Int, Int>>>

(如果 ROOM 预编译器不喜欢那里有 Pair<Int, Int>,请创建一个新数据 class,类似于 data class CaloriesInfo(val amount: Int, val caloriesBurned: Int) 并将其用作您的 return 数据类型相反)

这样你只需要一个 LiveData。

  1. 有时您可能有合法的用例需要将两个或多个 LiveData 合并在一起,在这种情况下您应该使用 MediatorLiveData.

类似于:

val mediator: MediatorLiveData<Pair<Int, Int>> = MediatorLiveData()

val liveData1 = repo.getLiveData()
val liveData2 = repo.getAnotherLiveData()

mediator.addSource(liveData1) { mediator.postValue(it to liveData2.value) }
mediator.addSource(liveData2) { mediator.postValue(liveData1.value to it) }

有时这样做有很好的理由,但我不建议您这样做,因为您需要做一些额外的事情才能以正确的格式获取数据对您进行绘图很有用。 LiveData 异步运行,因此当您尝试绘制事物时 x 和 y 来自不同的 LiveData 没有意义。你最好的选择仍然是做一个更好的 SQLite 查询,并在一个查询中完成。