使用来自不同数据源(网络和房间)的存储库模式将数据列表返回给 viewModel

returning a list of data to viewModel using Repository pattern from different data sources (network and room)

我正在使用带存储库模式的 MVVM 开发 Kotlin 应用程序。

我有一个显示小行星列表的主要片段。

这是我想要实现的流程。

所以根据我对存储库模式的理解,viewModel 不应该关心数据源是来自 API 还是本地数据库。

所以我在 viewModel 将调用的存储库中定义了这个函数

override suspend fun getAsteroid(): List<Asteroid> {
    var result : List<Asteroid>
    try {
        var isDataAvailable = getAnyAsteroidFromDb()
         if (isDataAvailable == null) {
             result = getAsteroidApi().asDomainModel()
         } else {
             result = getAsteroidFromDb()
         }
    } catch (e : Exception) {

    }
    return result
}

getAnyAsteroidFromDb 检查房间内的数据可用性

getAsteroidApi 从网络调用中获取数据

getAsteroidFromDb 从房间

获取数据

问题是 getAsteroidFromDb returns 来自 Dao 的 Livedata

 @Query("SELECT * FROM asteroid_tbl")
    fun getAsteroidsFromDb () : LiveData<List<AsteroidEntity>>

以及函数本身 getAsteroid returns 小行星列表。

假设我将 return 类型更改为 Livedata ,这将导致另一个问题,因为 api 不是 return Livedata。

我有点卡在这里,我想我做错了什么,或者我对 MVVM 和库模式的低估仍然不够好。

任何想法或想法将不胜感激!

您应该能够return LiveData 值:

override suspend fun getAsteroid(): List<Asteroid> {
var result : List<Asteroid>
try {
    var isDataAvailable = getAnyAsteroidFromDb()
     if (isDataAvailable == null) {
         result = getAsteroidApi().asDomainModel()
     } else {
         result = getAsteroidFromDb().value  //<==List<Asteroid>
     }
} catch (e : Exception) {

}
return result

}

对此有多种解决方案,但由于您使用的是 MVVM 模式。因此,我想向您推荐一种适用于这种情况的模式。

每当出现必须检查我们的本地数据库或调用我们的后端的情况时 API。通常的调用结构是只有一点数据源,避免歧义等问题。

因此,虽然您可以轻松地从 LiveData 获取 value 或将 API 响应转换为 LiveData。我建议你的结构如下。

  • 检查本地数据库中的数据。
  • 如果本地数据库中有数据,请获取它。
  • 如果本地数据库中没有数据,调用API,获取结果,将其存储在本地数据库中。
  • 在 API 结果成功后,您可以再次查询本地数据库并获得结果。

这确保您的单一事实来源仍然是您的数据库,并且您可以轻松地进行调用。

如果您不想 return 存储库中的实时数据,您可以解包从 Room 获取的实时数据并使用其中的值。那应该给你小行星对象的列表。所以,使用这样的东西:

override suspend fun getAsteroid(): List<Asteroid> {
    var result : List<Asteroid>
    try {
        var isDataAvailable = getAnyAsteroidFromDb()
         if (isDataAvailable == null) {
             result = getAsteroidApi().asDomainModel()
         } else {
             val data = getAsteroidFromDb()
             result = data.value
         }
    } catch (e : Exception) {

    }
    return result
}