【问题标题】:Kotlin Flow Offline CachingKotlin Flow 离线缓存
【发布时间】:2022-02-04 07:05:16
【问题描述】:

我是 kotlin flow 的新手,我正在处理这个文档。 Kotlin Flows。在这段代码中,数据源每五秒从 api 获取数据并发出它。

这是我的示例数据源类。

我正在获取数据并发送它。

class RemoteDataSourceImpl @Inject constructor(
private val api:CryptoApi
): RemoteDataSource {


override suspend fun cryptoList(): Flow<List<CryptoCoinDto>> {
    return flow {
        while (true){
            
            val data = api.getCoinList()
            emit(data)
            delay(5000L)
        }
    }
   }
}

这是我的示例存储库。

我正在映射数据并将其保存为房间数据库。由于单一事实来源原则,我想从房间数据库中获取数据并发出它,但我仍然必须返回 dataSource,因为如果我打开新流{},我无法访问数据源的数据。当然,我可以通过在 RemoteDataSource 类中使用 List 而不是 Flow 来解决问题。但我想了解这个例子。我如何在这里应用单一事实来源。

class CoinRepositoryImpl @Inject constructor(
private val dataSource:RemoteDataSource,
private val dao: CryptoDao
):CoinRepository {

override fun getDataList(): Flow<List<CryptoCoin>> {

     dataSource.cryptoList().map { dtoList ->
        val entityList = dtoList.map { dto ->
            dto.toCryptoEntity()
        }
        dao.insertAll(entityList)
    }
    return dataSource.cryptoList().map {
        it.map { it.toCryptoCoin() }
    }

}

【问题讨论】:

  • 所以你需要在两个不同的地方收集物品,对吗?
  • 我想将项目保存在房间数据库中,然后从数据库中收集它们并将其作为主数据发出。为单一事实来源原则。我可以管理单次获取,但这个示例有多个发射,我无法处理它。 @broot

标签: android kotlin repository kotlin-flow


【解决方案1】:

这实际上比看起来更复杂。流程旨在支持背压,这意味着它们通常只在被消费时按需生产项目。它们是被动的,而不是推动物品,而是从流程中拉出物品。

(免责声明:这对于冷流来说都是正确的,而不是热流。但cryptoList() 是冷流。)

这样设计的目的是大大简化消费者比生产者慢或根本没有人消费物品的情况。然后生产者停止生产,一切都很好。

在您的情况下,有两个消费者,所以这又更复杂了。如果一个消费者比另一个消费者慢,你需要决定应该发生什么。例如,如果没有人从getDataList() 收集数据会发生什么?有多种选择,每种方法都需要一些不同的方法:

  1. 停止使用源流,因此停止更新数据库。
  2. 如果没有人从getDataList() 收集,请始终更新数据库并将项目排队。如果队列中的项目越来越多怎么办?
  3. 如果没有人从 getDataList() 收集,请始终更新数据库并丢弃项目。

Ad.1.

可以使用onEach():

return dataSource.cryptoList().onEach {
    // update db
}.map {
    it.map { it.toCryptoCoin() }
}

在此解决方案中,更新数据库是使用 getDataList() 流的“副作用”。

广告 2。和 Ad.3。

在这种情况下,我们不能被动地等到有人向我们索要物品。我们需要主动消费源流中的项目并将它们推送到下游流。所以我们需要一个热流:SharedFlow。此外,因为在这种情况下我们仍然是主动方,所以我们必须启动一个协同程序,它将在后台执行此操作。所以我们需要一个CoroutineScope

解决方案取决于您的具体需求:您是否需要队列,如果队列超过大小限制会发生什么等,但它类似于:

return dataSource.cryptoList().onEach {
    // update db
}.map {
    it.map { it.toCryptoCoin() }
}.shareIn(scope, SharingStarted.Eagerly)

您还可以阅读 buffer()MutableSharedFlow - 它们可能对您有用。

【讨论】:

  • 我想,我明白了,但有些东西我无法理解。所有这些更新数据库和映射项都可以,但它仍然从 api 收集数据。我可以从房间收集数据并发出它吗?还是我认为完全错误?我对我认为的单一事实来源感到困惑。我只是想听实时更改并将其保存到数据库然后从数据库中收集它们并将它们发送到 ui。 @broot
猜你喜欢
  • 2018-03-28
  • 2010-11-15
  • 2018-08-06
  • 2015-05-05
  • 1970-01-01
  • 1970-01-01
  • 2011-12-09
  • 2016-12-16
  • 1970-01-01
相关资源
最近更新 更多