【问题标题】:Android architecture LiveData and RepositoriesAndroid 架构 LiveData 和存储库
【发布时间】:2020-03-16 02:14:16
【问题描述】:

我正在将我的应用程序转换为房间数据库,并尝试遵循基于“带视图的房间”的谷歌架构最佳实践。

我无法从干净架构的角度理解存储库。

Words 数据库示例仅包含一个表和一个使用它的视图,使其成为一个简单的 HelloWorld 示例。但让我们从那开始吧。

有一个显示单词列表的视图。因此,所有单词都需要从数据库中读取并显示。 所以我们有一个 MainActivity 和一个数据库要连接。

  1. 实体词
  2. WordDao 访问数据库
  3. WordViewModel:为了将活动生命周期与数据生命周期分开,使用了 ViewModel。
  4. WordRepository:因为数据可能保存在数据库或云中,或者为了处理数据来源而引入的任何存储库中。
  5. 视图活动

如果视图在数据变化时更新就好了,所以使用 LiveData。

这反过来意味着,存储库正在为整个表提供 LiveData:

// LiveData gives us updated words when they change.
val allWords: LiveData<List<Word>>

这对于单个视图来说很好。

现在是关于扩展这个概念的问题。

让我们假设,单词表有两列“word”和“last_updated”作为时间字符串。

为了方便比较,需要将时间字符串转换为毫秒,所以我有一个函数。

问题:在哪里放置有趣的 queryMaxServerDateMS() 以获得最大值(last_updated)?

/**
 * @return Highest server date in table in milliseconds or 1 on empty/error.
 */
fun queryMaxServerDateMS(): Long {
    val maxDateTime = wordDao.queryMaxServerDate()

    var timeMS: Long = 0
    if (maxDateTime != null) {
        timeMS = parseDateToMillisOrZero_UTC(maxDateTime)
    }
    return if (timeMS <= 0) 1 else timeMS
}

对我来说,将它放入 WordRepository 是很自然的。

第二个需求:后台作业更新数据库中的单词列表。

假设我现在想要一个定期安排的后台作业,它检查服务器是否有新条目并将它们下载到数据库中。该应用可能未打开。

这个问题只是转述了上面queryMaxServerDateMS的问题。

该作业将首先检查是否通过询问服务器是否存在比最大已知条目更新的条目来创建新条目。

所以我需要获取一个新类 WordRepository,进行查询,获取 max last_update 并询问服务器。

但是:我不需要后台作业中的 LiveData,并且当 val repositoy = WordRepository 读取完整表时,这是不必要的、时间、内存和电池消耗。

我还可以想到许多不同的片段,它们需要单词表的一些数据,但从不需要完整数据,想想列出一个产品的产品详细信息屏幕。

所以我可以将它移到另一个存储库或 DbHelper,但你想调用它。

但最后我想知道,如果我使用 LiveData,它需要 View、ViewModel 和 Repository 紧密耦合在一起:

问题:我是否需要为每个活动/片段创建一个存储库,而不是为每个表创建一个存储库,这样更合乎逻辑?

【问题讨论】:

    标签: android android-room android-architecture-components repository-design


    【解决方案1】:
    1. 是的,对于您当前的架构,您应该将其放在Repository 中。
    2. 不,您不需要每个活动/片段的存储库。最好为 1 个实体创建 1 个存储库。您可以为每个 ViewModel 分配一个 UseCase

    在 Clean 架构中有一个 UseCase / Interactor 的概念,它可以包含业务逻辑,在 Android 中它可以充当ViewModelRepository 之间的附加层,您可以为您的函数创建一些 UseCase 类@987654328 @,把它放在那里,然后从你需要的任何ViewModel 调用它。

    您还可以通过调用getValue() 同步获取您的LiveData 值。

    【讨论】:

    • 谢谢。但是对于 2) 我仍然在使用 LiveData 时调用它。我查看了谷歌示例,它们似乎为您所谓的用例创建了一个存储库。
    • @GunnarBernstein 也许您正在查看的示例很旧,但所有新示例都使用每 1 个实体 1 个存储库或用例。看看这些,它们得到了积极的维护:github.com/android/architecture-samples - 它有多种架构变化。以及最近带有 UseCases 的 Google I/O 应用程序github.com/google/iosched
    【解决方案2】:

    您不需要每个活动或片段的存储库。要回答有关获得最大服务器时间的问题 - 当您从 db 加载单词时,您几乎可以访问整个表。这意味着您可以自己进行计算以确定添加的最新单词,或者您可以通过在 dao 中添加另一个查询并在您的存储库中访问它来将该工作委托给房间。为了简单起见,我更喜欢后者。

    要回答您有关在不同活动或片段中使用 repo 的问题 - room 缓存您的计算,以便它们可用于您的 repo 的不同用户(最终是 dao)。这意味着如果您已经计算了一个活动中的最大服务器时间并在那里使用了它,那么其他生命周期所有者可以使用该计算结果,只要表没有被更改(可能还有其他条件)

    总结一下,对于表而不是活动或片段,您是正确的

    【讨论】:

    • 不是我的问题的真正答案。 a) 对于服务器时间,我使用 wordDao.queryMaxServerDate(),问题是,如何在不调用 allWords 的情况下获得服务器时间。 b) 是的,我知道它会缓存。但我需要一个用例存储库来避免缓存该表不需要的 LiveData。
    • 对于 a) 我没有说你需要使用 allWords 来获得最大服务器时间。您将不得不在您的 dao(使用 sql 查询)中创建另一个端点,该端点会为您计算。 b)如果您在上面执行“a)”,那么您并没有真正缓存“不需要”的 allWords。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-02
    • 1970-01-01
    • 2017-12-26
    • 2012-02-13
    • 2017-05-12
    • 2019-04-17
    相关资源
    最近更新 更多