试图用房间flowable @ rxjava + retrofit2实现MVVM。
当活动开始时,我从存储库中请求一个项目列表。仓库从数据库(room)中检索它们,并将Flowable返回给ViewModel。在同一时刻,存储库从API中请求当前的列表,一旦返回结果,我就删除数据库中现有的条目,并插入从API到达的内容。
当然,活动中的观察者会三次更新recyclerview。正因为如此,ui在更新列表的时候会 "闪烁":the list is not empty -> the list is empty -> the list is not empty.
观察者在第一次从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;
}
});
我不是Room专家,也许有这么一个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();
}
在这种情况下,你只需要从数据库中获取第一个值 (take(1)
),然后等待API的值。
switchMap
(也可以是 flatMap
在此,无异 这个 的情况下)保证你的DB值将是第一位的,只有在 "监听 "API之后。
这里唯一的问题是,如果你假设在其他地方更新DB值,而这个活动正在运行。在这种情况下,这个更新将不会被显示。