我正在将我的应用程序转换为房间数据库,并尝试遵循基于“带景观的房间”的谷歌架构最佳实践。
我无法从干净的架构方面理解存储库。
Words 数据库示例仅包含一个表和一个使用它的 View ,使其成为一个简单的 HelloWorld 示例。但让我们从那个开始吧。
有一个显示单词列表的 View 。因此需要从数据库中读取所有单词并显示出来。 所以我们有一个 MainActivity 和一个要连接的数据库。
- 实体词
- WordDao 访问数据库
- WordViewModel:使用 ViewModel 将 Activity 生命周期与数据生命周期分开。
- WordRepository:由于数据可能保存在数据库或云端或任何引入的存储库中以处理决策,因此数据来自何处。
- 与 View 一起 Activity
如果数据变化时 View 也更新就好了,所以用了LiveData。
这反过来意味着,存储库正在为整个表提供 LiveData:
// LiveData gives us updated words when they change.
val allWords: LiveData<List<Word>>
这对于单个 View 来说没问题。
现在回答我关于扩展这个概念的问题。
让我们假设,单词表有两列“word”和“last_updated”作为时间字符串。
为了便于比较,时间字符串需要转换为毫秒,所以我有一个函数。
问题:将有趣的 queryMaxServerDateMS() 放在哪里以获得 max(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 时会读取整个表,这是不必要的,而且会耗费时间、内存和电池。
我还可以想到许多不同的 fragment ,这些 fragment 需要单词表的一些数据,但不需要完整的数据,比如列出一个产品的产品详细信息屏幕。
所以我可以将它移到另一个 Repository 或 DbHelper,无论您如何调用它。
但最后我想知道,如果我使用 LiveData,它需要 View、ViewModel 和 Repository 紧密耦合在一起:
问题:我是否需要为每个 Activity/fragment 创建一个存储库,而不是为每个表创建一个存储库,这会更符合逻辑吗?
最佳答案
- 是的,根据您当前的架构,您应该将其放入
Repository
。 - 不,您不需要为每个 Activity/fragment 创建一个存储库。最好为 1 个实体创建 1 个存储库。每个
ViewModel
都可以有一个UseCase
。
在Clean架构中有一个UseCase/Interactor的概念,它可以包含业务逻辑,在Android中它可以作为ViewModel
和Repository
之间的附加层,你可以为您的函数 queryMaxServerDateMS()
创建一些 UseCase 类,将它放在那里并从您需要的任何 ViewModel
调用它。
您还可以通过调用 getValue()
同步获取您的 LiveData
值。
关于Android 架构 LiveData 和 Repositories,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58953029/