Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxJavaを1年使って見えてきたこと

 RxJavaを1年使って見えてきたこと

CAMPFIRE Android #1で発表した「RxJavaを1年使って見えてきたこと」のスライドです
https://yj-meetup.connpass.com/event/53419/

Naoto Nakazato

April 19, 2017
Tweet

More Decks by Naoto Nakazato

Other Decks in Technology

Transcript

  1. 自己紹介 • Naoto Nakazato • Yahoo Japan Corporation • Yahoo!知恵袋

    • アカウント ◦ Twitter: @oxsoft ◦ Facebook: naoto.nakazato ◦ GitHub: oxsoft ◦ Qiita: oxsoft
  2. アプリの基本構成 • Application ◦ Modelのインスタンスを保持 • Model ◦ データの保持(BehaviorSubject) ◦

    APIリクエストの組み立てと実行 ◦ APIレスポンスを内部で使う Beanクラスに変換 • Activity ◦ Application経由でModelにアクセス ◦ ユーザーアクションに応じて Modelにリクエスト ◦ ModelからObservableを取得し表示系を更新する • ApiRequest/ApiResponse ◦ Modelのみ利用 • Bean ◦ ModelからActivityに情報を渡すのに利用 API Model Activity Request Response Bean
  3. 非同期処理が楽 public Single<Result> request(Param... params) { return Single.create((Single.OnSubscribe<Result>) singleSubscriber ->

    { // 非同期処理 try { singleSubscriber.onSuccess(new Result()); } catch (Exception e) { singleSubscriber.onError(e); } }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); } API Request 通信処理(非同期処理)をRxでラップしている OSSを使えば勝手にやってくれることも多い
  4. 非同期処理が楽 public Single<Bean> request(Param... params) { return request(...).map(result -> bean);

    } Model request(...).subscribe(bean -> { // 終わった後の処理 }, throwable -> { // 例外処理 }); Activity レスポンスクラスをデータクラスに変換(腐敗防止層的なこと) 適宜キャッシュを返したりする データを受け取って、表示更新処理などを行う。エラー時の挙動も書く
  5. 複数箇所で最新の情報を表示 private BehaviorSubject<String> studentName = BehaviorSubject.create(); private void setName(String name)

    { studentName.onNext(name); } public String getName() { return studentName.getValue(); } public Observable<String> getNameObservable() { return studentName.asObservable(); } ModelにBehaviorSubjectを保持し、観測用の関数を用意する ”観測可能な”変数のように扱える
  6. doOnTerminate() for Single public static <T> Single<T> doOnTerminate(Single<T> single, Action0

    onTerminate) { return Single.create(singleSubscriber -> single.subscribe(value -> { onTerminate.call(); singleSubscriber.onSuccess(value); }, error -> { onTerminate.call(); singleSubscriber.onError(error); })); } 成功しても失敗しても実行する処理を書く(ObservableにあるものをSingleに実装) ※RxJava1ではSingleのlift()がprivateなので、上記のような実装をしています
  7. ProgressDialogを簡単に出す public <T> Single<T> progress(Single<T> single) { ProgressDialog progressDialog =

    new ProgressDialog(this); progressDialog.show(); return doOnTerminate(single, progressDialog::dismiss); } 以下のようにすれば、簡単にProgressDialogが表示できる progress(request(...)).subscribe(...)
  8. 二重をリクエスト防止する private List<Requestable> requests = new ArrayList<>(); protected <T> Single<T>

    singleRequest(Requestable<T> requestable) { if (requests.contains(requestable)) { return Single.error(new DuplicateRequestException()); } requests.add(requestable); return doOnTerminate(requestable.request(), () -> requests.remove(requestable)); } • リクエスト中でなければ、リクエストする • リクエスト中ならば、エラーを返す
  9. 通信要求と通信状態は分けるべきだった void requestProfile(int userId) Observable<RequestState> observeProfileRequestState(int userId) Observable<Profile> observeProfile(int userId)

    リクエストの要求、リクエスト状態の監視、結果の監視に分けると良さそう リクエスト状態とリクエスト結果を分けているのは、 キャッシュを即座に表示しつつ、最新の情報を取得する時などに有効
  10. unsubscribeする場所が良くなかった protected void onCreate(Bundle savedInstanceState) { model.requestProfile(userId); } protected void

    onStart() { model.observeProfileRequestState(userId).subscribe(requestState -> {...}); model.observeProfile(userId).subscribe(profile -> {...}); } protected void onStop() { unsubscribe(); } ※ただしDialogFragmentの表示は、onSaveInstanceStateの後だとダメなので、  タイミングをずらすなど別途対策をする必要があります
  11. ストリームに流す値はimmutableにすべきだった • オブジェクトを受け取った側で状態を変更するのがご法度なのは当たり前 • インスタンスを使いまわすとdistinctUntilChangedなどがおかしくなる public void updateStudentName(String name) {

    Student student = studentSubject.getValue(); student.setName(name); // Student is mutable! studentSubject.onNext(student); } ※distinctは内部でHashSet(ハッシュ値)を使っているのでこの問題が顕在化しにくいです
  12. まとめ • 通信要求と通信状態は分ける • unsubscribeする場所をよく考える • ストリームにはimmutableを流す • ストリームにはnullは流さない •

    Listっぽいものの扱いに注意する • RxJava2に移行する • ついでにKotlin化も ご清聴ありがとうございました