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

问题描述 投票:0回答:1

试图用房间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;
    }
});
android retrofit2 rx-java android-room
1个回答
0
投票

我不是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值,而这个活动正在运行。在这种情况下,这个更新将不会被显示。

© www.soinside.com 2019 - 2024. All rights reserved.