使用Flowable(RxJava)时如何避免不必要的RecyclerView渲染?

时间:2020-06-02 06:53:24

标签: android retrofit2 rx-java android-room

尝试使用可流通的@ 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;
    }
});

1 个答案:

答案 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值。在这种情况下,将不会显示此更新。

相关问题