【Potatotips #30】RxJavaを活用する3つのユースケース

1,735 views

Published on

2016/06/23(Thu)に開催された potatotips #30 (http://potatotips.connpass.com/event/32665/) での発表資料です。

Published in: Technology

【Potatotips #30】RxJavaを活用する3つのユースケース

  1. 1. Androidアプリ開発で RxJavaを活用する 3つのユースケース Hiroyuki Kusu ( @hkusu_ ) 2016/06/23 potatotips #30
  2. 2. ①非同期処理の結果うけとり ②イベントの送信/購読 ③データの変更監視 ※今回はデータ加工、FRP的な話はしません ※本スライド上のサンプルコードは Java 8 および Retrolambda の利用を前提としています
  3. 3. ①非同期処理の結果うけとり ②イベントの送信/購読 ③データの変更監視
  4. 4. doSomethingAsnc() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(aStringList -> { // … 結果を受け取って何か }); コールバックを廃して同期的に書ける Observable<T>を返す非同期な処理
  5. 5. Observable.create(subscriber -> { // ... 裏スレッドで何か subscriber.onNext("something"); subscriber.onCompleted(); }) .subscribeOn(Schedulers.io()) // 裏スレッドを指定 .observeOn(AndroidSchedulers.mainThread()) // メインスレッドを指定 .subscribe(res -> { // ... メインスレッドで結果を受け取って何か }); ちなみに重たい処理を裏スレッドで実行させたい 時にも使える(AsyncTask、AsyncTaskLoaderの替り)
  6. 6. ①非同期処理の結果うけとり ②イベントの送信/購読 ③データの変更監視
  7. 7. 購読側 イベント仲介用のクラス (シングルトン) Subject 送信側 早い話が Otto や EventBus のようなもの コールバックを引き回すのが煩雑な場合に (例:Activity 間の通知、ListViewの操作イベント取得など) イベントの送信 イベントの購読
  8. 8. public class RxEventBus { private final Subject<Object, Object> subject = new SerializedSubject<>(PublishSubject.create()); public <T> Subscription onEvent(Class<T> clazz, Action1<T> handler) { return subject .ofType(clazz) .subscribe(handler); } public void post(Object event) { subject.onNext(event); } } RxEventBus.java(前項におけるイベント仲介用のクラス) 内部にSubjectを保持 継続的にイベントを発生させるには Subject を用いる
  9. 9. public class RxEventBus { private final Subject<Object, Object> subject = new SerializedSubject<>(PublishSubject.create()); public <T> Subscription onEvent(Class<T> clazz, Action1<T> handler) { return subject .ofType(clazz) .subscribe(handler); } public void post(Object event) { subject.onNext(event); } } RxEventBus.java(前項におけるイベント仲介用のクラス) イベントの購読用メソッド イベントクラス名でフィルタ
  10. 10. public class RxEventBus { private final Subject<Object, Object> subject = new SerializedSubject<>(PublishSubject.create()); public <T> Subscription onEvent(Class<T> clazz, Action1<T> handler) { return subject .ofType(clazz) .subscribe(handler); } public void post(Object event) { subject.onNext(event); } } RxEventBus.java(前項におけるイベント仲介用のクラス) イベントの送信用メソッド
  11. 11. rxEventBus.post(new SomeEvent()); rxEventBus.onEvent(SomeEvent.class, event -> { // … 結果を受け取って何か }); イベントの送信 イベントの購読 イベント仲介用のクラスのインスタンスを共有(シングルトン等)し ておけば、アプリケーションのどこからでもイベントを送れる
  12. 12. ①非同期処理の結果うけとり ②イベントの送信/購読 ③データの変更監視
  13. 13. データを保持するクラス Subject購読側 購読 データ変更
  14. 14. public class SomeRepository { private final Subject<String, String> subject = new SerializedSubject<>(PublishSubject.create()); public final Observable<String> getObservable() { return subject; } private void notify(String string) { subject.onNext(string); } // ... 以降、CRUDのコード } 内部にSubjectを保持 SomeRepository.java(前項におけるデータを保持するクラス)
  15. 15. public class SomeRepository { private final Subject<String, String> subject = new SerializedSubject<>(PublishSubject.create()); public final Observable<String> getObservable() { return subject; } private void notify(String string) { subject.onNext(string); } // ... 以降、CRUDのコード } SomeRepository.java(前項におけるデータを保持するクラス) SubjectをObservable<T> として外部へ公開
  16. 16. public class SomeRepository { private final Subject<String, String> subject = new SerializedSubject<>(PublishSubject.create()); public final Observable<String> getObservable() { return subject; } private void notify(String string) { subject.onNext(string); } // ... 以降、CRUDのコード } SomeRepository.java(前項におけるデータを保持するクラス) データ変更を通知する private メソッド ※データのCRUD時に notify() をコールする規則とする
  17. 17. someRepository.getObservable() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(aString -> { // ... 結果を受け取って何か }); 購読側 データが変更される度にストリームが 流れてくる
  18. 18. データを保持するクラス Activity/ Fragment 購読 ビューへの反映 何かしらの CRUD操作 データ 『データに対する』ビューの描画処理が宣言的に定義できる。 データの流れが一方向なので分かりやすい 関心の分離
  19. 19. TIPS
  20. 20. ・購読の一括解除ができる ・Activity の onPause() 等で購読を停止 したい場合、一度 unscribe() すると add() できなくなる問題 ⇒ unsubscribe() でなく clear() を使う CompositeSubscription
  21. 21. doSomethingAsnc() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(aStringList -> { // ... 結果を受け取って何か }); 型名を示す変数名をつけると分かりやすいかも? Retrolambda を利用していてストリーム中 のデータの型がよく分からなくなる問題 例)List<String> の場合
  22. 22. public class Tuple3<T1, T2, T3> { private final T1 t1; private final T2 t2; private final T3 t3; private Tuple3(T1 t1, T2 t2, T3 t3) { this.t1 = t1; this.t2 = t2; this.t3 = t3; } public T1 get1() { return t1; } public T2 get2() { return t2; } public T3 get3() { return t3; } public static <T1, T2, T3> Tuple3<T1, T2, T3> create(T1 t1, T2 t2, T3 t3) { return new Tuple3<>(t1, t2, t3); } } 3つ以上の時は Tuple 的なクラスを用意する Observable<T> で複数の値を扱いたい場合 Observable<Pair<String, List<Integer>>> 2つの場合は Pair が使える
  23. 23. Sample code hkusu/android-rxjava-app-sample
  24. 24. THANKS!
  25. 25. 予備スライド
  26. 26. Activity/Fragment UseCase層 Repository層 Service層 (AndroidのServiceではない) DI DI DI Observable<T> Observable<T> Observable<T> 裏スレッド( Schedulers.io() )で実行 メインスレッド ( AndroidSchedulers .mainThread() )で購読

×