我首先要说我已经阅读了一百万个博客,观看了一千个视频,但我对页面越来越感到困惑。在输入所有这些内容时胡思乱想有助于我解决一些问题。
TL; DR 主要问题是如何为 UI 层和通常(在方法中内联)检索数据的反应性(使用后台线程)对于已经在后台线程上调用您的方法的业务层方法。您的 Repo 和 Dao 是否需要多种方法来执行相同的查询?
@Query("Select * from Product WHERE Product.ProductId = :id")
ProductDb getForId(Integer id);
@Query("Select * from Product WHERE Product.ProductId = :id")
LiveData<ProductDb> getForIdLive(Integer id);
@Query("Select * from Product WHERE Product.ProductId = :id")
Maybe<ProductDb> getForIdRx(Integer id);
使用 MVVM 架构。来自新 Android 架构组件的 ViewModel 实现负责处理生命周期问题,所以让我们使用它。
使用 Room 数据库组件实现的数据库 - 所有设置都完美运行,这就是如何在我的应用程序中检索不同层的数据,这让我很困扰。
我们将举一个简单的例子,通过 Id 从数据库中检索产品。
LiveData 如果您只想在 UI 中显示数据,此选项似乎很好。您的活动或片段创建 ViewModel,设置等待数据的观察者。
// get an instance of the viewmodel
mMyViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
// Setup an observer on the Product. This will tell us when one is loaded.
final Observer<Product> productObserver = new Observer<Product>() {
@Override
public void onChanged(Product product) {
doSomethingWithProduct(product);
}
};
然后可以通过调用 ViewModel 中的方法来加载产品,响应被吐出到我们在观察者中设置的 doSomethingWithProduct()
mMyViewModel.getProductById(productId).observe(this,productObserver);
ViewModel 有一个方法
public LiveData<Product> getProductById(int id) {
return mReferenceDataRepository.loadProductById(id);
}
存储库有一个非常相似的方法
public LiveData<Product> loadProductById(int id) {
return mProductDao.loadProductById(id);
}
最后是 Room 架构的 Dao 作为一种方法来进行实际的数据库检索。
@Query("SELECT * from Product WHERE ProductId = :id")
LiveData<Product> loadProductById(int id);
我们使用从数据库到 Observer 的 LiveData,一切都很顺利。因为 Dao 是 LiveData,所以检索是在后台线程上完成的,该线程负责处理 Room 吐出的 ANR。对于检索数据以进行简单显示,这条路线似乎很完美。
然而,并非一切都与 UI 有关!
该应用程序比这更复杂。我正在将库存项目添加到库存中,并且基于存储在产品/位置等中的几个业务规则,我可能需要将其放入隔离区或拒绝它。
Activity 不应该实现这些业务规则,它的工作是简单地与用户沟通,另外可能有几个 Activity 可以添加库存项目
ViewModel 不应该实现这些业务规则,多个活动可能需要相同的规则。
存储库不应该实现这些业务规则——应该吗?
我会在 StockItemBL(业务层)中实现这些规则。AddItemToStock 方法。
现在我需要从数据库加载产品,但我不想要 LiveData<>。我不想以响应式方式加载产品,我不需要在 BusinessLayer 中响应式,当您需要加载多个 Db 表来执行业务逻辑时它就不起作用。我只想要一个好的旧时尚
Product p = mReferenceDataRepository.loadProductById(productId);
Location l = mReferenceDataRepository.loadLocationById(locationId);
if (p.getQuarantine())....
if (l.getIsQuarantine())....
但该方法返回一个 LiveData,而不仅仅是一个 POJO 产品 我现在需要在存储库中使用另一个方法吗?
我也以同样的方式看待 RxJava。
你可以从 Dao 返回一个 Maybe,事实上,Rx 更容易管理异常。但它有同样的问题——你的存储库和 Dao 中是否需要单独的方法。
事实上,使用 Repository 的原因是您可以切换实现。如果您的方法公开 LiveData 或 Maybe 那么您真的可以轻松切换实现吗?