初心者のための RxJava

初心者のための RxJava

本セッションでは、最近 Android アプリ開発で注目を浴びている Reactive Extension (Rx) と呼ばれる非同期処理を扱うライブラリについて簡単に説明し、さらに RxJava を例に、それをどのように実際の開発に活用していくかを解説します。

Rx はその考え方を理解するまでに時間がかかること、オペレータやコンセプトが多すぎて、どのように適切に使えば良いか分からないことから、学習コストが高いと言われています。本セッションでは、そのような Rx 初心者のために、Rx のコアとなる概念と併せて具体的な利用方法や効果的な学習法について説明いたします。

参考:
- Reactive programming - Wikipedia, the free encyclopedia
https://en.wikipedia.org/wiki/Reactive_programming

- JJUG ナイトセミナーで Reactive Streams について発表しました

http://okapies.hateblo.jp/entry/2015/06/26/024505

- ReactiveX
http://reactivex.io/

- Exploring RxJava 2 for Android (GOTOcph October 2016)

https://speakerdeck.com/jakewharton/exploring-rxjava-2-for-android-gotocph-october-2016

- Reactive Programming with JDK 9 Flow API
https://community.oracle.com/docs/DOC-1006738

979d93b360f80486b121486a9d063ad5?s=128

Hiroshi Kurokawa

October 09, 2016
Tweet

Transcript

  1. 9.

    3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1) 3FBDUJWF   Y " # $ 5SBOTGPSNBUJPOBM
  2. 10.

    3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1)   Y " # $   5SBOTGPSNBUJPOBM 3FBDUJWF
  3. 11.

    3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1)   Y " # $    5SBOTGPSNBUJPOBM 3FBDUJWF
  4. 12.

    3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1) A = 3   Y " # $    5SBOTGPSNBUJPOBM 3FBDUJWF
  5. 13.

    3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1) A = 3   Y " # $    5SBOTGPSNBUJPOBM 3FBDUJWF
  6. 14.

    3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1) A = 3   Y " # $    5SBOTGPSNBUJPOBM 3FBDUJWF
  7. 18.

    ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ network.getDataA(new NetworkCall.Listener<String>() {
 @Override public void success(String data) {


    network.getDataB(data, new NetworkCall.Listener<String>() {
 @Override public void success(String data) {
 }‌
 });
 }
 });
  8. 19.

    ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ network.getDataA(new NetworkCall.Listener<String>() {
 @Override public void success(String data) {


    network.getDataB(data, new NetworkCall.Listener<String>() {
 @Override public void success(String data) {
 tv.setText(data);
 }‌
 });
 }
 });
  9. 20.

    ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ network.getDataA(new NetworkCall.Listener<String>() {
 @Override public void success(String data) {


    network.getDataB(data, new NetworkCall.Listener<String>() {
 @Override public void success(String data) {
 tv.setText(data);
 }‌
 
 @Override public void failure(Throwable t) {}
 });
 }
 
 @Override public void failure(Throwable t) {}
 });
  10. 21.

    ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ network.getDataA(new NetworkCall.Listener<String>() {
 @Override public void success(String data) {


    network.getDataB(data, new NetworkCall.Listener<String>() {
 @Override public void success(String data) {
 if (!isDestroyed()) {
 tv.setText(data);
 }
 }‌
 
 @Override public void failure(Throwable t) {}
 });
 }
 
 @Override public void failure(Throwable t) {}
 });
  11. 22.

    ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ network.getDataA(new NetworkCall.Listener<String>() {
 @Override public void success(String data) {


    network.getDataB(data, new NetworkCall.Listener<String>() {
 @Override public void success(String data) {
 runOnUiThread(() -> {
 if (!isDestroyed()) {
 tv.setText(data);
 }
 });
 }‌
 
 @Override public void failure(Throwable t) {}
 });
 }
 
 @Override public void failure(Throwable t) {}
 });
  12. 45.

    3FBDUJWF&YUFOTJPO 3Y הכ 1 2 3 4 5 6 <

    > GPSxJO JGx % 2 == 0UIFO QVTIx * x UP list FOE FOE SFUVSOlist
  13. 46.

    3FBDUJWF&YUFOTJPO 3Y הכ 1 2 3 4 5 6 <

    > GJMUFS x % 2 == 0  NBQ x -> x * x
  14. 48.
  15. 49.

    3FBDUJWF&YUFOTJPO 3Y הכ 1 2 3 4 5 6 GJMUFS

    x % 2 == 0  NBQ x -> x * x 4 16 36
  16. 50.

    3FBDUJWF&YUFOTJPO 3Y הכ 4 16 36 Observable.just(1, 2, 3, 4,

    5, 6)
 .filter(x -> x % 2 == 0)
 .map(x -> x * x)
 .subscribe(System.out ::println);
  17. 53.

    3Y+BWBד⡦ָדֹ׷ךַ network.getDataA(new NetworkCall.Listener<String>() {
 @Override public void success(String data) {


    network.getDataB(data, new NetworkCall.Listener<String>() {
 @Override public void success(String data) {
 runOnUiThread(() -> {
 if (!isDestroyed()) {
 tv.setText(data);
 }
 });
 }
 
 @Override public void failure(Throwable t) {}
 });
 }
 
 @Override public void failure(Throwable t) {}
 });
  18. 60.

    @Override public void onCreate(Bundle savedInstanceState) { …
 subscription = network.getDataA()


    .subscribeOn(Schedulers.io())
 .flatMap(data -> network.getDataB(data))
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(
 data -> tv.setText(data),
 throwable -> Log.e(TAG, throwable.getMessage())
 );
 } 3Y+BWBד⡦ָדֹ׷ךַ
  19. 61.

    @Override public void onCreate(Bundle savedInstanceState) { …
 subscription = network.getDataA()


    .subscribeOn(Schedulers.io())
 .flatMap(data -> network.getDataB(data))
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(
 data -> tv.setText(data),
 throwable -> Log.e(TAG, throwable.getMessage())
 );
 }
 @Override public void onDestroy() {
 super.onDestroy();
 subscription.unsubscribe();
 } 3Y+BWBד⡦ָדֹ׷ךַ
  20. 62.

    @Override public void onCreate(Bundle savedInstanceState) { …
 subscription = network.getDataA()


    .subscribeOn(Schedulers.io())
 .flatMap(data -> network.getDataB(data))
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(
 data -> tv.setText(data),
 throwable -> Log.e(TAG, throwable.getMessage())
 );
 }
 @Override public void onDestroy() {
 super.onDestroy();
 subscription.unsubscribe();
 } 3Y+BWBד⡦ָדֹ׷ךַ
  21. 66.

    8JUIPVU3Y+BWB private void setup() {
 input1.addTextChangedListener(new TextWatcher() {
 @Override public

    void onTextChanged(CharSequence s, int start, int before, int count) {
 input1Valid = s.length() > 0;
 validate();
 }
 });
 … }
 
 private void validate() {
 button.setEnabled(input1Valid && input2Valid && input3Valid);
 } 3Y+BWBד⡦ָדֹ׷ךַ
  22. 67.

    8JUI3Y+BWB private void setup() {
 ArrayList<Observable<Boolean >> validators = new

    ArrayList <>();
 validators.add(RxTextView.textChanges(input1).map(s -> s.length() > 0));
 … 
 Observable.combineLatest(validators, args -> {
 for (Object a : args) {
 if (!(Boolean) a) return false;
 }
 return true;
 }).subscribe(button ::setEnabled);
 } 3Y+BWBד⡦ָדֹ׷ךַ
  23. 68.

    8JUI3Y+BWB private void setup() {
 ArrayList<Observable<Boolean >> validators = new

    ArrayList <>();
 validators.add(RxTextView.textChanges(input1).map(s -> s.length() > 0));
 … 
 Observable.combineLatest(validators, args -> {
 for (Object a : args) {
 if (!(Boolean) a) return false;
 }
 return true;
 }).subscribe(button ::setEnabled);
 } 3Y+BWBד⡦ָדֹ׷ךַ
  24. 69.

    8JUI3Y+BWB private void setup() {
 ArrayList<Observable<Boolean >> validators = new

    ArrayList <>();
 validators.add(RxTextView.textChanges(input1).map(s -> s.length() > 0));
 … 
 Observable.combineLatest(validators, args -> {
 for (Object a : args) {
 if (!(Boolean) a) return false;
 }
 return true;
 }).subscribe(button ::setEnabled);
 } 3Y+BWBד⡦ָדֹ׷ךַ
  25. 70.

    8JUI3Y+BWB private void setup() {
 ArrayList<Observable<Boolean >> validators = new

    ArrayList <>();
 validators.add(RxTextView.textChanges(input1).map(s -> s.length() > 0));
 … 
 Observable.combineLatest(validators, args -> {
 for (Object a : args) {
 if (!(Boolean) a) return false;
 }
 return true;
 }).subscribe(button ::setEnabled);
 } 3Y+BWBד⡦ָדֹ׷ךַ
  26. 82.

    3Y+BWBד⡦ָדֹ׷ךַ أؙٗ٦ָٕꟚ㨣׃׋׵ꬊず劍Ⳣ椚׾⨡姺ׅ׷ final Subscription s = idling.startWith(true)
 .filter(b -> b)


    .flatMap(aBool -> serivce.getData()) .takeUntil(idling.filter(b -> !b))
 .repeatWhen(completes -> completes.switchMap(
 c -> idling.filter(b -> b)))
 .subscribe(l -> showLog("Success!"));
  27. 83.

    3Y+BWBד⡦ָדֹ׷ךַ أؙٗ٦ָٕꟚ㨣׃׋׵ꬊず劍Ⳣ椚׾⨡姺ׅ׷ final Subscription s = idling.startWith(true)
 .filter(b -> b)


    .flatMap(aBool -> serivce.getData()) .takeUntil(idling.filter(b -> !b))
 .repeatWhen(completes -> completes.switchMap(
 c -> idling.filter(b -> b)))
 .subscribe(l -> showLog("Success!"));
  28. 85.

    3Y+BWBד⡦ָדֹ׷ךַ أؙٗ٦ָٕ⨡姺׃׋׵ⱄTVCTDSJCFׅ׷ final Subscription s = idling.startWith(true)
 .filter(b -> b)


    .flatMap(aBool -> serivce.getData()) .takeUntil(idling.filter(b -> !b))
 .repeatWhen(completes -> completes.switchMap(
 c -> idling.filter(b -> b)))
 .subscribe(l -> showLog("Success!"));
  29. 87.

    final Subscription s = idling.startWith(true)
 .filter(b -> b)
 .flatMap(aBool ->

    serivce.getData()) .takeUntil(idling.filter(b -> !b))
 .repeatWhen(completes -> completes.switchMap(
 c -> idling.filter(b -> b)))
 .subscribe(l -> showLog("Success!")); 3Y+BWBד⡦ָדֹ׷ךַ 㹋遤ׅ׷أٖحس׾䭷㹀ׅ׷
  30. 88.

    3Y+BWBד⡦ָדֹ׷ךַ 㹋遤ׅ׷أٖحس׾䭷㹀ׅ׷ final Subscription s = idling.startWith(true)
 .subscribeOn(Schedulers.io())
 .filter(b ->

    b)
 .flatMap(aBool -> serivce.getData())
 .takeUntil(idling.filter(b -> !b))
 .repeatWhen(completes -> completes.switchMap(
 c -> idling.filter(b -> b)))
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(l -> showLog("Success!"));
  31. 89.

    3Y+BWBד⡦ָדֹ׷ךַ ConnectableObservable<Boolean> idling =
 RxAbsListView.scrollEvents(listView)
 .map(event -> event.scrollState()
 == AbsListView.OnScrollListener.SCROLL_STATE_IDLE)


    .distinctUntilChanged()
 .publish();
 subscriptions.add(idling.connect());
 
 subscriptions.add(idling.startWith(true)
 .subscribeOn(Schedulers.io())
 .filter(b -> b)
 .flatMap(aBool -> serivce.getData())
 .takeUntil(idling.filter(b -> !b))
 .repeatWhen(completes -> completes.switchMap( c -> idling.filter(b -> b)))
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(l -> showLog("Success!")));
  32. 91.

    ًٔحز ˖ ؎كٝزװꬊず劍Ⳣ椚ָ䪔ְװְׅ ˖ 朐䡾㢌侧ָ㼰זֻג幥׬ ˖ ر٦ةؿٗ٦ך鋅鸐׃ָ葺ֻז׷ رًٔحز ˖ 湫䠬涸הכꣲ׵זְ

    ˖ ⢪ְֿזׅחכ䢪׸ָ䗳銲 ˖ ➬穈׫׾椚鍑׃גְזְה縐ח䅹׶װְׅ 3Y+BWBךًٔحزرًٔحز
  33. 94.

    ˖ ؔلٖ٦ةָ׋ֻׁ׿֮׷ ז׈㷕统؝أزָ넝ְךַ all() amb() ambWith() and() asyncAction() asyncFunc() averageDouble()

    averageFloat() averageInteger() averageLong() buffer() cache() cast() chunkify() collect() combineLatest() concat() concatMap() concatWith() connect() contains() count() countLong() create() debounce() defaultIfEmpty() defer() deferFuture() deferCancellableFuture() delay() dematerialize() distinct() distinctUntilChanged() doOnCompleted() doOnEach() doOnError() doOnNext() doOnRequest() doOnSubscribe() doOnTerminate() doOnUnsubscribe() doWhile() elementAt() elementAtOrDefault() empty() error() exists() filter() finallyDo() first() firstOrDefault() flatMap() flatMapIterable() forEach() forIterable() from() fromAction() fromCallable() fromCancellableFuture() fromFunc0() fromFuture() fromRunnable() generate() generateAbsoluteTime() getIterator() groupBy() groupByUntil() groupJoin() ifThen() ignoreElements() interval() isEmpty() join() just() last() lastOrDefault()
  34. 100.

    ˖ $SFBUJOH ˖ 5SBOTGPSNJOH ˖ 'JMUFSJOH ˖ $PNCJOJOH ˖ &SSPS)BOEMJOH

    ˖ $POEJUJPOBMBOE#PPMFBO ˖ .BUIFNBUJDBMBOE"HHSFHBUF ؔلٖ٦ةךؕذ؞ٔ׾濼׷
  35. 102.

    ˖ 0CTFSWBCMFDSFBUF ד0CTFSWBCMF׾⡲׵זְֿה☠ ˖ ׋ְגְך׮ךכٓ؎ـٓٔח֮׷ ˖ طحزٙ٦ؙ鸐⥋̔3FUSPGJU ˖ 42-̔42-#SJUF 0SNB

    ˖ 6*؎كٝز̔3Y#JOEJOH ˖ וֲ׃ג׮זְ㜥さכ0CTFSWBCMFGSPN9 ׾⢪ֲ ˖ GSPN$BMMBCMF  ˖ GSPN&NJUUFS ٓ؎ـٓٔ׾ⵃ欽ׅ׷
  36. 108.

    ˖ 3FBDUJWFQSPHSBNNJOH8JLJQFEJB UIFGSFFFODZDMPQFEJB
 IUUQTFOXJLJQFEJBPSHXJLJ3FBDUJWF@QSPHSBNNJOH ˖ ++6(ش؎زإىش٦ד3FBDUJWF4USFBNTחאְג涪邌׃ת׃׋
 IUUQPLBQJFTIBUFCMPKQFOUSZ ˖ 3FBDUJWF9
 IUUQSFBDUJWFYJP

    ˖ &YQMPSJOH3Y+BWBGPS"OESPJE (050DQI0DUPCFS 
 IUUQTTQFBLFSEFDLDPNKBLFXIBSUPOFYQMPSJOHSYKBWBGPS BOESPJEHPUPDQIPDUPCFS ˖ 3FBDUJWF1SPHSBNNJOHXJUI+%,'MPX"1*
 IUUQTDPNNVOJUZPSBDMFDPNEPDT%0$ ⿫罋