尝试使用可流通的@ rxjava + retrofit2实现MVVM。
活动开始时,我从存储库中请求项目列表。存储库从数据库(房间)检索它们,并将Flowable返回给ViewModel。同时,存储库从API请求当前列表,并在返回结果后立即删除数据库中的现有条目,并插入从API获取的内容。
活动中的观察者当然会更新recyclerview三次。因此,ui在更新列表时“闪烁”: 列表不为空->列表为空->列表不为空。
首次收到来自Room的可流动对象后,观察者将收到一个空列表(在删除数据库中的条目时),然后将其从API插入数据库后再收到一个新列表。
如何避免RecyclerView的这种行为?是否有完善的最佳做法,正确的方法等?
PaymentRepository方法,用于获取付款清单:
private Flowable<List<Payment>> getPayments(Long accountId) {
// requesting actual data from API
paymentService.getPayments().flatMapCompletable(payments -> paymentDao
.deleteAllByAccountId(accountId)
.andThen(paymentDao.insert(payments))
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
).subscribe();
// and return cached list from db
return paymentDao.findPaidByAccountId(accountId)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
ViewModel
private CompositeDisposable disposable = new CompositeDisposable();
public MutableLiveData<Resource<List<Payment>>> result = new MutableLiveData<>(Resource.loading());
public PaymentListViewModel() {
disposable.add(
paymentRepository.getPayments().subscribe(
payments -> result.setValue(Resource.success(payments)),
throwable -> result.setValue(paymentService.parseError(throwable).toResource())
)
);
}
活动中的观察者
viewModel.result.observe(this, resource -> {
switch (resource.status) {
case SUCCESS:
adapter.setItems(resource.data);
binding.preloader.setVisibility(View.GONE);
break;
case ERROR:
Toast.makeText(this, resource.message, Toast.LENGTH_LONG).show();
binding.preloader.setVisibility(View.GONE);
break;
case LOADING:
binding.preloader.setVisibility(View.VISIBLE);
break;
}
});
答案 0 :(得分:0)
我不是会议室专家,也许有RX方法可以更新值而不将其发送给侦听器。 但这是不要求它的方式:
private Flowable<List<Payment>> getPayments(Long accountId) {
// requesting actual data from API
Flowable<List<Payment>> request = paymentService.getPayments()
.flatMapCompletable(payments -> paymentDao
.deleteAllByAccountId(accountId)
.andThen(paymentDao.insert(payments))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
);
return paymentDao.findPaidByAccountId(accountId)
.take(1)
.switchMap(dbList -> request.startWith(dbList))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.distinctUntilChanged();
}
在这种情况下,您仅从DB(take(1)
)中获取第一个值,然后等待API中的值。
switchMap
(此处也可能是flatMap
,在这种情况下没有区别)保证DB值将是第一个,并且仅在“监听” API之后。
这是唯一的问题,如果您想在此Activity运行时在其他地方更新DB值。在这种情况下,将不会显示此更新。