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

初心者のための 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. ⴱ䗰罏ך׋׭ך 3Y+BWB 랲䊛峔 吳䒭⠓爡'BCMJD  !IZESBLFDBU

  2. 3Y+BWB ˖ 3Y 3FBDUJWF&YUFOTJPO ך+BWB㹋鄲

  3. 3Y+BWB ˖ 3Y 3FBDUJWF&YUFOTJPO ך+BWB㹋鄲 3FBDUJWF

  4. 3FBDUJWF1SPHSBNNJOHהכ ˑBQSPHSBNNJOHQBSBEJHNPSJFOUFEBSPVOEEBUBGMPXTBOEUIF QSPQBHBUJPOPGDIBOHF˒ 3FBDUJWFQSPHSBNNJOH8JLJQFEJB IUUQTFOXJLJQFEJBPSHX JOEFYQIQ UJUMF3FBDUJWF@QSPHSBNNJOHPMEJE ˑ3FBDUJWFQSPHSBNTBMTPNBJOUBJOBDPOUJOVPVTJOUFSBDUJPOXJUI UIFJSFOWJSPONFOU CVUBUBTQFFEXIJDIJTEFUFSNJOFECZUIF

    FOWJSPONFOU OPUUIFQSPHSBNJUTFMG˒ 3FBDUJWFQSPHSBNNJOH8JLJQFEJB IUUQTFOXJLJQFEJBPSHXJLJ3FBDUJWF@QSPHSBNNJOH
  5. 3FBDUJWF1SPHSBNNJOHהכ ˑ3FBDUJWFQSPHSBNTBMTPNBJOUBJOBDPOUJOVPVTJOUFSBDUJPOXJUI UIFJSFOWJSPONFOU CVUBUBTQFFEXIJDIJTEFUFSNJOFECZUIF FOWJSPONFOU OPUUIFQSPHSBNJUTFMG˒ 3FBDUJWFQSPHSBNNJOH8JLJQFEJB IUUQTFOXJLJQFEJBPSHXJLJ3FBDUJWF@QSPHSBNNJOH ˑBQSPHSBNNJOHQBSBEJHNPSJFOUFEBSPVOEEBUBGMPXTBOEUIF QSPQBHBUJPOPGDIBOHF˒

    3FBDUJWFQSPHSBNNJOH8JLJQFEJB IUUQTFOXJLJQFEJBPSHX JOEFYQIQ UJUMF3FBDUJWF@QSPHSBNNJOHPMEJE
  6. 3FBDUJWF1SPHSBNNJOHהכ ˑBQSPHSBNNJOHQBSBEJHNPSJFOUFEBSPVOEEBUBGMPXTBOEUIF QSPQBHBUJPOPGDIBOHF˒ 3FBDUJWFQSPHSBNNJOH8JLJQFEJB IUUQTFOXJLJQFEJBPSHXJLJ3FBDUJWF@QSPHSBNNJOH 5SBOTGPSNBUJPOBM 㢌䳔㘗 㢌侧ח㼎ׅ׷乼⡲׾אא鎸鶢

  7. 3FBDUJWF1SPHSBNNJOHהכ ˑBQSPHSBNNJOHQBSBEJHNPSJFOUFEBSPVOEEBUBGMPXTBOEUIF QSPQBHBUJPOPGDIBOHF˒ 3FBDUJWFQSPHSBNNJOH8JLJQFEJB IUUQTFOXJLJQFEJBPSHXJLJ3FBDUJWF@QSPHSBNNJOH 5SBOTGPSNBUJPOBM 㢌䳔㘗 㢌侧ח㼎ׅ׷乼⡲׾אא鎸鶢 3FBDUJWF ر٦ةؿٗ٦׾㹑鎉׃גַ׵ծ㢌刿׾⠗乄ׇׁ׷

  8. 5SBOTGPSNBUJPOBM 3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C =

    (A + 1) x (B - 1)
  9. 3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1) 3FBDUJWF   Y " # $ 5SBOTGPSNBUJPOBM
  10. 3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1)   Y " # $   5SBOTGPSNBUJPOBM 3FBDUJWF
  11. 3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1)   Y " # $    5SBOTGPSNBUJPOBM 3FBDUJWF
  12. 3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1) A = 3   Y " # $    5SBOTGPSNBUJPOBM 3FBDUJWF
  13. 3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1) A = 3   Y " # $    5SBOTGPSNBUJPOBM 3FBDUJWF
  14. 3FBDUJWF1SPHSBNNJOHהכ A = 2 B = 3 C = (A

    + 1) x (B - 1) A = 3   Y " # $    5SBOTGPSNBUJPOBM 3FBDUJWF
  15. ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ network.getDataA();

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


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


    network.getDataB(data);
 }
 });
  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) {
 }‌
 });
 }
 });
  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);
 }‌
 });
 }
 });
  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) {}
 });
  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) {}
 });
  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) {}
 });
  23. ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ

  24. ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ

  25. ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ

  26. ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ

  27. ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ

  28. ז׈"OESPJE،فٔꟚ涪ד31ָ岣湡ׁ׸׷ךַ

  29. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  30. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  31. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  32. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  33. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM subscribe

  34. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  35. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  36. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  37. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM completed

  38. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  39. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM Observable subscribe(Subscriber)

  40. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM Observable subscribe(Subscriber) Subscriber

    onNext() onCompleted() onError()
  41. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  42. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  43. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM

  44. 3FBDUJWF&YUFOTJPO 3Y הכ BMJCSBSZGPSDPNQPTJOHBTZODISPOPVTBOEFWFOUCBTFE QSPHSBNTVTJOHPCTFSWBCMFTFRVFODFT˒ 3FBDUJWF9*OUSP IUUQSFBDUJWFYJPJOUSPIUNM Operator

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

    > GPSxJO JGx % 2 == 0UIFO QVTIx * x UP list FOE FOE SFUVSOlist
  46. 3FBDUJWF&YUFOTJPO 3Y הכ 1 2 3 4 5 6 <

    > GJMUFS x % 2 == 0  NBQ x -> x * x
  47. 3FBDUJWF&YUFOTJPO 3Y הכ 1 2 3 4 5 6

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

    x % 2 == 0  NBQ x -> x * x
  49. 3FBDUJWF&YUFOTJPO 3Y הכ 1 2 3 4 5 6 GJMUFS

    x % 2 == 0  NBQ x -> x * x 4 16 36
  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);
  51. ˖ ꬊず劍Ⳣ椚 ˖ 6*؎كٝزⳢ椚 ˖ ꬊず劍Ⳣ椚 6*؎كٝزⳢ椚 3Y+BWBד⡦ָדֹ׷ךַ

  52. ˖ ꬊず劍Ⳣ椚 ˖ 6*؎كٝزⳢ椚 ˖ ꬊず劍Ⳣ椚 6*؎كٝزⳢ椚 3Y+BWBד⡦ָדֹ׷ךַ

  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) {}
 });
  54. network.getDataA(); 3Y+BWBד⡦ָדֹ׷ךַ

  55. network.getDataA()
 .subscribe(
 data -> tv.setText(data),
 throwable -> Log.e(TAG, throwable.getMessage())
 );

    3Y+BWBד⡦ָדֹ׷ךַ
  56. network.getDataA()
 .flatMap(data -> network.getDataB(data))
 .subscribe(
 data -> tv.setText(data),
 throwable ->

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

    -> Log.e(TAG, throwable.getMessage())
 ); 3Y+BWBד⡦ָדֹ׷ךַ
  58. 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ד⡦ָדֹ׷ךַ
  59. 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ד⡦ָדֹ׷ךַ
  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ד⡦ָדֹ׷ךַ
  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ד⡦ָדֹ׷ךַ
  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ד⡦ָדֹ׷ךַ
  63. 3Y+BWBד⡦ָדֹ׷ךַ

  64. ˖ ꬊず劍Ⳣ椚 ˖ 6*؎كٝزⳢ椚 ˖ ꬊず劍Ⳣ椚 6*؎كٝزⳢ椚 3Y+BWBד⡦ָדֹ׷ךַ

  65. 6*؎كٝزⳢ椚 ׅץגWBMJE׌׏׋㜥さך׫ TVCNJUنةٝ׾FOBCMFחׅ׷ 3Y+BWBד⡦ָדֹ׷ךַ

  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ד⡦ָדֹ׷ךַ
  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ד⡦ָדֹ׷ךַ
  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ד⡦ָדֹ׷ךַ
  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ד⡦ָדֹ׷ךַ
  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ד⡦ָדֹ׷ךַ
  71. 3Y+BWBד⡦ָדֹ׷ךַ

  72. ˖ ꬊず劍Ⳣ椚 ˖ 6*؎كٝزⳢ椚 ˖ ꬊず劍Ⳣ椚 6*؎كٝزⳢ椚 3Y+BWBד⡦ָדֹ׷ךַ

  73. 3Y+BWBד⡦ָדֹ׷ךַ ꬊず劍Ⳣ椚 6*؎كٝزⳢ椚 ꬊず劍Ⳣ椚 6*؎كٝزⳢ椚

  74. 3Y+BWBד⡦ָדֹ׷ךַ ꬊず劍Ⳣ椚 6*؎كٝزⳢ椚 أؙٗ٦ָٕ⨡姺׃׋׵ꬊず 劍Ⳣ椚׾㨣׭ծأؙٗ٦ָٕ Ꟛ㨣׃׋׵װ׭׷ ؕؐٝزָחז׏׋׵ 穠卓ָ邌爙ׁ׸׷

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


    .distinctUntilChanged()
 .publish(); أؙٗ٦ٕךꟚ㨣⨡姺׾嗚濼ׅ׷0CTFSWBCMF
  76. 3Y+BWBד⡦ָדֹ׷ךַ ConnectableObservable<Boolean> idling =
 RxAbsListView.scrollEvents(listView)
 .map(event -> event.scrollState()
 == AbsListView.OnScrollListener.SCROLL_STATE_IDLE)


    .distinctUntilChanged()
 .publish(); أؙٗ٦ٕךꟚ㨣⨡姺׾嗚濼ׅ׷0CTFSWBCMF
  77. 3Y+BWBד⡦ָדֹ׷ךַ

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

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


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


    .flatMap(aBool -> serivce.getData())
 .subscribe(l -> showLog("Success!"));
  81. 3Y+BWBד⡦ָדֹ׷ךַ أؙٗ٦ָٕꟚ㨣׃׋׵ꬊず劍Ⳣ椚׾⨡姺ׅ׷ final Subscription s = idling.startWith(true)
 .filter(b -> b)


    .flatMap(aBool -> serivce.getData())
 .subscribe(l -> showLog("Success!"));
  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!"));
  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!"));
  84. 3Y+BWBד⡦ָדֹ׷ךַ

  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!"));
  86. 3Y+BWBד⡦ָדֹ׷ךַ

  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ד⡦ָדֹ׷ךַ 㹋遤ׅ׷أٖحس׾䭷㹀ׅ׷
  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!"));
  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!")));
  90. ًٔحز ˖ ؎كٝزװꬊず劍Ⳣ椚ָ䪔ְװְׅ ˖ 朐䡾㢌侧ָ㼰זֻג幥׬ ˖ ر٦ةؿٗ٦ך鋅鸐׃ָ葺ֻז׷ 3Y+BWBךًٔحزرًٔحز

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

    ˖ ⢪ְֿזׅחכ䢪׸ָ䗳銲 ˖ ➬穈׫׾椚鍑׃גְזְה縐ח䅹׶װְׅ 3Y+BWBךًٔحزرًٔحز
  92. ז׈㷕统؝أزָ넝ְךַ

  93. ˖ ؔلٖ٦ةָ׋ֻׁ׿֮׷ ז׈㷕统؝أزָ넝ְךַ

  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()
  95. ˖ ؔلٖ٦ةָ׋ֻׁ׿֮׷ ˖ װװֿ׃ְ嚊䙀 ז׈㷕统؝أزָ넝ְךַ

  96. ˖ ؔلٖ٦ةָ׋ֻׁ׿֮׷ ˖ װװֿ׃ְ嚊䙀 ˖ )PU$PME0CTFSWBCMF ˖ 4DIFEVMFS ˖ 4VCTDSJQUJPO

    ˖ 4VCKFDU ˖ #BDLQSFTTVSF ז׈㷕统؝أزָ넝ְךַ
  97. سًُؗٝز׾铣׬ ؔلٖ٦ةך⹛ֹ׾䗰ד椚鍑ׅ׷ ؔلٖ٦ةךؕذ؞ٔ׾濼׷ ٓ؎ـٓٔ׾ⵃ欽ׅ׷ 嚂׃׬ 3Y+BWBך㷕统岀

  98. 3FBDUJWF93Y+BWB8JLJ IUUQTHJUIVCDPN3FBDUJWF9 3Y+BWBXJLJ *OUSPEVDUJPOUP3Y IUUQXXXJOUSPUPSYDPN 3Y4BNQMFT IUUQSYXJLJXJLJEPUDPN TBNQMFT سًُؗٝز׾铣׬

  99. 3Y+4ד鑐ׅ ˖ &4 #BCFM  ˖ IUUQTKTGJEEMFOFUIZESBLFDBUGUWQIO ؔلٖ٦ةך⹛ֹ׾䗰ד椚鍑ׅ׷

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

    ˖ $POEJUJPOBMBOE#PPMFBO ˖ .BUIFNBUJDBMBOE"HHSFHBUF ؔلٖ٦ةךؕذ؞ٔ׾濼׷
  101. א⟃♳ך0CTFSWBCMF׾⢪ְ׋ְ 
 ̔$PNCJOJOH$POEJUJPOBM אך0CTFSWBCMFח׃ַ莆㄂ָזְ 
 ̔5SBOTGPSNJOH'JMUFSJOH 0CTFSWBCMF׾⡲׶׋ְ 
 ̔$SFBUJOH ؔلٖ٦ةךؕذ؞ٔ׾濼׷

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

    ˖ 6*؎كٝز̔3Y#JOEJOH ˖ וֲ׃ג׮זְ㜥さכ0CTFSWBCMFGSPN9 ׾⢪ֲ ˖ GSPN$BMMBCMF  ˖ GSPN&NJUUFS ٓ؎ـٓٔ׾ⵃ欽ׅ׷
  103. 嚂׃׬ IUUQTMJEFTDPNSPCXPSNBMEFWFSZUIJOHJTBTUSFBN ˖ 걧ך⢪ְ倯ָ殯ז׷ ˖ ֲתֻ剅ֽ׷הֲ׸׃ְ ˖ 㔭׏׋׵BOESPJEKQ4MBDLפ
 IUUQTBOESPJEKQIFSPLVBQQDPN

  104. ˖ 3Y+BWB3$ ˖ 3FBDUJWF4USFBNTك٦أ ˖ 'JOBM3FMFBTFTDIFEVMFEBUUI0DU 3Y+BWBךֿ׸ַ׵

  105. ˖ 3Y+BWB3$ ˖ 3FBDUJWF4USFBNTك٦أ ˖ 'JOBM3FMFBTFTDIFEVMFEBUUI0DU 3Y+BWBךֿ׸ַ׵ 3FBDUJWF4USFBNT

  106. ˖ +BWBדך垥彊⻉ KVD'MPX  ˖ IUUQTDPNNVOJUZPSBDMFDPNEPDT%0$ ˖ 彊䬿׃גְ׷ٓ؎ـٓٔ ˖ "LLB4USFBNT

    ˖ 3FBDUPS ˖ 3Y+BWB 3FBDUJWF4USFBNT
  107. ˖ +BWBדך垥彊⻉ KVD'MPX  ˖ IUUQTDPNNVOJUZPSBDMFDPNEPDT%0$ ˖ 彊䬿׃גְ׷ٓ؎ـٓٔ ˖ "LLB4USFBNT

    ˖ 3FBDUPS ˖ 3Y+BWB 3FBDUJWF4USFBNT ״׶أةٝت٦سח
  108. ˖ 3FBDUJWFQSPHSBNNJOH8JLJQFEJB UIFGSFFFODZDMPQFEJB
 IUUQTFOXJLJQFEJBPSHXJLJ3FBDUJWF@QSPHSBNNJOH ˖ ++6(ش؎زإىش٦ד3FBDUJWF4USFBNTחאְג涪邌׃ת׃׋
 IUUQPLBQJFTIBUFCMPKQFOUSZ ˖ 3FBDUJWF9
 IUUQSFBDUJWFYJP

    ˖ &YQMPSJOH3Y+BWBGPS"OESPJE (050DQI0DUPCFS 
 IUUQTTQFBLFSEFDLDPNKBLFXIBSUPOFYQMPSJOHSYKBWBGPS BOESPJEHPUPDQIPDUPCFS ˖ 3FBDUJWF1SPHSBNNJOHXJUI+%,'MPX"1*
 IUUQTDPNNVOJUZPSBDMFDPNEPDT%0$ ⿫罋
  109. 5IBOL:PV 랲䊛峔 吳䒭⠓爡'BCMJD  !IZESBLFDBU https://github.com/hkurokawa https://speakerdeck.com/hkurokawa