Загрузка данных Реактивный / нереактивный, LiveData, RxJava
Я начну с того, что прочитал миллион блогов, посмотрел тысячу видео, и страница меня все больше смущает... Волнение при наборе всего этого помогает мне решить некоторые вопросы.
TL; DR Основной вопрос заключается в том, как оперативно получать данные (используя фоновые потоки) для уровня пользовательского интерфейса И обычно (встроенный в метод) для методов бизнес-уровня, где ваш метод уже был вызван в фоновом потоке. Нужно ли вашим Repo's & 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. Реализация ViewModel из новых компонентов архитектуры Android решает проблемы жизненного цикла, поэтому давайте воспользуемся этим.
База данных, реализованная с использованием компонентов базы данных Room - все настроено на работу отлично, меня беспокоит то, как получать данные на разных уровнях моего приложения.
Мы возьмем простой пример получения продукта из базы данных по идентификатору.
LiveData Эта опция подходит для отображения данных в пользовательском интерфейсе. Ваша деятельность или фрагмент создает ViewModel, настраивает Observer, который ожидает данные.
// 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);
}
и, наконец, архитектура Dao of the Room как метод для фактического поиска в базе данных.
@Query("SELECT * from Product WHERE ProductId = :id")
LiveData<Product> loadProductById(int id);
Мы используем LiveData из базы данных в Observer, и все работает. Поскольку Dao - это LiveData, поиск выполняется в фоновом потоке, который заботится о ANR, который будет выделен Room. Для извлечения данных для простого отображения этот маршрут кажется идеальным.
Однако не все касается пользовательского интерфейса!
Приложение более сложное, чем это. Я добавляю товар Stock на склад и основываясь на нескольких бизнес-правилах, которые хранятся в Product/Location и т. Д. Мне может понадобиться поместить его в карантин или отклонить.
Действие не должно реализовывать эти бизнес-правила, его задача - просто общаться с пользователем, плюс может быть несколько действий, которые могут добавить элемент товара
ViewModel не должен реализовывать эти бизнес-правила, одно и то же правило может потребоваться для нескольких операций.
Репозиторий не должен реализовывать эти бизнес-правила - не так ли?
Я бы реализовал эти правила в StockItemBL (бизнес-уровень). Метод AddItemToStock.
Теперь мне нужно, чтобы Продукт загружался из БД, но я не хочу LiveData<>. Я не хочу загружать продукт реактивно, мне не нужно реагировать в Business Layer, и он просто не работает, когда вам нужно загрузить несколько таблиц БД для выполнения бизнес-логики. Я просто хочу старую добрую моду
Product p = mReferenceDataRepository.loadProductById(productId);
Location l = mReferenceDataRepository.loadLocationById(locationId);
if (p.getQuarantine())....
if (l.getIsQuarantine())....
но этот метод возвращает LiveData, а не просто продукт POJO. Теперь мне нужен другой метод в репозитории?
Я также смотрел на RxJava в том же духе.
Вы можете вернуть Maybe из Dao, и на самом деле Rx проще управлять исключениями. Но у него тот же вопрос - нужны ли вам отдельные методы в ваших репозиториях и Dao.
Фактически, причина использования репозитория в том, что вы можете отключить реализацию. Если ваши методы предоставляют LiveData или Maybe, можете ли вы действительно легко переключить реализацию?