Android
android開発
RxJava
SwipeRefreshLayout

Rxで非同期処理とプログレス表示切り替えを分離する

雑記事です。

  1. 画面遷移時に画面にプログレスを表示して、データ取得待ちを表示したい
  2. SwipeRefreshLayoutで画面をリフレッシュできるようにしたい

この2つを満たしつつ、2種類のプログレスの表示制御をするのがめんどくさくねというところから始まりました。

1は画面にプログレスを出したい、2はSwipeRefreshLayoutのプログレスを利用したいという感じです。
非同期処理自体は全く同じですが、トリガーが違うみたいな状態。

public class FooFragment extends Fragment {

    FragmentFooBinding dataBinding;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        dataBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_foo, container, false);

        // adapterとかの初期化

        dataBinding.swipeRefreshLayout.setOnRefreshListener(() -> {
            refresh().subscribe(dataBinding.swipeRefreshLayout::setRefreshing);
        });

        return dataBinding.getRoot();
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        refresh().subscribe(loading -> {
            dataBinding.progress.setVisibility(loading ? View.VISIBLE : View.GONE);
        });
    }

    private Subject<Boolean> refresh() {
        Subject<Boolean> loadingSubject = BehaviorSubject.create();

        mApiService.topics()
                .compose(bindUntilEvent(FragmentEvent.DESTROY_VIEW))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(disposable -> loadingSubject.onNext(true))
                .doFinally(() -> loadingSubject.onNext(false))
                .subscribe(
                        response -> {
                            adapter.setData(response.topics);
                        },
                        throwable -> Log.e(TAG, "fetch: ", throwable)
                );

        return loadingSubject;
    }
}

Observableの進捗を通知してやってSubjectで返せば、処理を共通化しつつ、呼び出す側でプログレスを制御できるんじゃないかなっていうアプローチです。