Androidアプリ開発からみた RxJavaの使いどころ

Androidアプリ開発からみた RxJavaの使いどころ

JJUG CCC 2017 Spring #ccc_i3

002c7b95e7b8f34186ffd6abaa136a99?s=128

Naoki Morioka

May 16, 2017
Tweet

Transcript

  1. "OESPJEΞϓϦ։ൃ͔ΒΈͨ 3Y+BWBͷ࢖͍Ͳ͜Ζ ++6($$$4QSJOH /BPLJ.PSJPLB

  2. ΤϯδχΞྺ೥໨ $ݴޠΛ೥΄Ͳɺޙ͸΄ͱΜͲ+BWB ࠷ۙ͸"OEPSJEJ04ΞϓϦ։ൃ ੝Ԭঘه !O@NPSJPLB IUUQTHJUIVCDPNONPSJPLB "CPVU.F ϑϦϡʔגࣜձࣾۈ຿ژ౎ࡏॅ

  3. ࢲͷ3Y+BWB΁ͷϞνϕʔγϣϯ w ؔ਺ܕzతzͳॲཧͷѻ͍͕Մೳ খ͍͞ॲཧΛ૊Έ߹Θͤͯେ͖ͳॲཧΛهड़͍ͯ͘͠ +BWBͰهड़ग़དྷͯ΄Ͳྑ͍όϥϯεײ֮ w ࢖ͬͯΈΔͱ৭ʑͱ৽͍͠ൃݟ͕͋Δ qBU.BQ[JQDPNCJOF-BUFTUͳͲͷར༻

  4. ར༻͍ͯ͠Δόʔδϣϯ w +%,@ w 3Y+BWB w 4QSJOH#PPU#6*-%4/"14)05 w 3FBDUPSɿ#6*-%4/"14)05

  5. ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ʹ͍ͭͯ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w

    ·ͱΊ
  6. w +BWB7.্Ͱಈ࡞͢Δ؍ଌՄೳ 0CTFSWBCMF ͳ࣌ܥྻσʔλ Λ༻͍ͨɺඇಉظͳΠϕϯτϕʔεͷϓϩάϥϛϯά ϦΞΫςΟ ϒϓϩάϥϛϯά ΛՄೳʹ͢ΔϥΠϒϥϦ w +BWBҎ্Ͱར༻Մೳ

    w ݱঢ়ͷϝΠϯ͸3Y+BWBܥ w 3Y+BWB3FBDUJWF&YUFOTJPOT 3FBDUJWF4USFBNT 8IBU`T3Y+BWBʁ
  7. ϦΞΫςΟϒϓϩάϥϛϯάᶃ w ͋ΔσʔλετϦʔϜʹରͯ͠ ͍ͭ͘Δ͔Θ͔Βͳ͍ σʔ λʹ൓ԠతʹϓϩάϥϛϯάΛߦ͏͜ͱ σʔλ ࣌ܥྻʹԊͬͨྲྀΕετϦʔϜ σʔλ ʜ

  8. ϦΞΫςΟϒϓϩάϥϛϯάᶄ w 3Y+BWBʹ͓͍ͯ͸+BWBΠϯελϯεͷ͕ͭͭσʔλ 4USFBN"1*ͱಉ͡ " # $ 4USJOHσʔλ " "

    " # $ # # $ $ # $ " # $ " # $ -JTUσʔλ
  9. ϦΞΫςΟϒϓϩάϥϛϯάᶅ w σʔλετϦʔϜͷੜ੒΍ɺม׵ɺ߹੒Λߦ͏ w ετϦʔϜ͔ΒདྷΔσʔλΛड͚औͬͨॲཧ ߪಡ Λهࡌ͢Δ " # $

    Πϕϯτ " " Πϕϯτ ʜ B C D B B 4USJOH ͂ TUP-PXFS$BTF ม׵ 4ZTUFNPVUQSJOUMO ߪಡ B C D ʜ
  10. w ϚΠΫϩιϑτࣾʹΑͬͯఏএ͞Εͨɺෳࡶͳඇಉظॲཧ΍Πϕ ϯτॲཧɺ͕࣌ؒؔ܎͢ΔॲཧͳͲΛهड़Ͱ͖Δ"1*܊ͷ࢓༷ w /&5΍+4ͳͲ֤छ࣮૷͕͋Δ w େ͖͍࢓༷ 3FBDUJWF&YUFOTJPOT 3Y IUUQTHJUIVCDPN3FBDUJWF&YUFOTJPOT

  11. w ϊϯϒϩοΩϯάͳ#BDL1SFTTVSFΛ༻͍ͨඇಉظετϦʔϜॲཧͷ࢓༷ w ͭͷΠϯλʔϑΣʔεఆٛͷఏڙ 1VCMJTIFS 4VCTDSJCFS 4VCTDSJQUJPO 1SPDFTTPS w 5FTU4VJUFͷఏڙ

    5$,  w খ͍͞࢓༷ 3FBDUJWF4USFBNT
  12. 3FBDUJWF4USFBNTΠϯλʔϑΣʔε Publisher public void subscribe(Subscriber<? super T> s); Subscriber public

    void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); /EBUBSFRVFTU /EBUBTUSFBNJOH TVCTDSJCF Subscription public void request(long n); public void cancel(); 1VCMJTIFS͕σʔλΛྲྀ͠4VCTDSJCFS͕σʔλΛड͚औΔॲཧ͕جຊ Processor public interface Processor<T, R> extends Subscriber<T>, Publisher<R> { }
  13. #BDL1SFTTVSF w ड৴ଆ͔Βૹ৴ଆ΁ͷσʔλϑϩʔ੍ޚ w ॲཧ͕ऴΘͬͨ͜ͱΛ఻͑ͯ࣍ͷσʔλΛऔಘ͢Δ w ૹ৴ଆͷσʔλੜ੒ͷํ͕଎͍৔߹͸4USBUFHZʹैͬͨॲཧ࣮ࢪ w ࿈݁΍߹੒΋Մೳ ॲཧ͖ͬͨ͠ͷͰ࣍Լ͍͞

    data 0, #BDL1SFTTVSF 4USBUFHZ #6''&3 %301 -"5&45 &3303 /0/& Publisher Subscriber
  14. ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ʹ͍ͭͯ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w

    ·ͱΊ
  15. 3Y+BWBͷίΞ 'MPXBCMF0CTFSWBCMF

  16. 'MPXBCMF0CTFSWBCMFͱ͸Կ͔ʁ w σʔλͷετϦʔϜΛੜ࢈ͯ͠ɺอ࣋͢ΔೖΕ෺ͷΑ͏ͳ΋ͷɻ ߪಡ TVCTDSJCF Մೳ 'MPXBCMF͸1VCMJTIFSΛ࣮૷ɺ#BDL1SFTTVSF੍ޚ͋Γɹ 0CTFSWBCMF͸#BDL1SFTTVSF੍ޚͳ͠ɻύϑΥʔϚϯε͸ྑ͍ w ͭͷঢ়ଶΛߪಡऀʹ఻͑Δɹ

    4VCTDSJCF/FYU$PNQMFUF&SSPS w ͭͷੑ࣭Λ࣋ͭ )PU $PME
  17. ̐ͭͷঢ়ଶ w 4VCTDSJCF͸௨஌ͷ४උ͕ग़དྷͨঢ়ଶ w /FYU͸σʔλ͕ྲྀΕ͍ͯΔঢ়ଶɻσʔλ಺༰͕ϋϯυϦϯά͞ΕΔ w $PNQMFUF͸ਖ਼ৗऴྃɻετϦʔϜʹσʔλ͕ྲྀΕͳ͘ͳΔ w &SSPS͸ҟৗऴྃɻετϦʔϜʹσʔλ͸ྲྀΕͳ͘ͳΔ OFYU

    OFYU OFYU OFYU OFYU DPNQMFUF OFYU OFYU FSSPS TVCTDSJCF TVCTDSJCF
  18. ߪಡॲཧ Flowable.just("1", "2", "3", "4") .subscribe(new Subscriber<String>() { public void

    onSubscribe(Subscription subscription) { subscription.request(Long.MAX_VALUE); System.out.println("subscribed"); } public void onNext(String s) { int num = Integer.parseInt(s); System.out.println(num); } public void onError(Throwable throwable) { System.out.println("error"); } public void onComplete() { System.out.println("completed"); } }); TVCTDSJCFE     DPNQMFUFE SFTVMU ੜ੒ ᶃ։࢝ ᶄσʔλऔಘ ᶅਖ਼ৗऴྃ
  19. ߪಡॲཧ ؔ਺ܕ*OUFSGBDF +BWB Flowable.just("1", "2", "3", "4")
 .subscribe(s -> {


    int num = Integer.parseInt(s);
 System.out.println(num);
 }, throwable -> {
 System.out.println("error : " + throwable.getMessage());
 });     SFTVMU /FYUॲཧϋϯυϦϯά Τϥʔॲཧ
  20. ߪಡॲཧ ؔ਺ܕ*OUFSGBDF +BWB public final Disposable subscribe(Consumer<? super T> onNext,

    Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Subscription> onSubscribe) { LambdaSubscriber<T> ls = new LambdaSubscriber( onNext, onError, onComplete, onSubscribe); this.subscribe((FlowableSubscriber)ls); return ls; } ಺෦తʹ4VCTDSJCFSΛ࡞੒ͯ͠ॲཧ͍ͯ͠Δ
  21. 'MPXBCMFͱ+BWB4USFBN"1*ͱͷҧ͍ w 'MPXBCMF͸࠶ར༻Մೳ w 'MPXBCMF͸࣮ߦ5ISFBEΛॲཧ్தͰ੾Γସ͑Մೳ w ྫ֎ͷѻ͍ 4USFBN"1*͸֎ଆʹ఻ൖ͢Δ 'MPXBCMF͸಺෦Ͱॲཧ͢Δ͜ͱ͕Մೳ

  22. 4USFBN"1* ࠶ར༻ෆՄ Stream<String> st = Arrays.asList("1", "2", "3", "4").stream();
 st.forEach(s

    -> {
 System.out.println(s);
 }); System.out.println(“next"); 
 st.forEach(s -> {
 System.out.println(s);
 });     OFYU KBWBMBOH*MMFHBM4UBUF&YDFQUJPOTUSFBNIBTBMSFBEZCFFOPQFSBUFEVQPOPSDMPTFE  BUKBWBVUJMTUSFBN"CTUSBDU1JQFMJOFJOJU "CTUSBDU1JQFMJOFKBWB  ʜ SFTVMU
  23. 'MPXBCMF ࠶ར༻Մೳ Flowable<String> flowable = Flowable.just("1", "2", "3", "4"); flowable.subscribe(s

    -> { System.out.println(s); }); System.out.println("next"); flowable.subscribe(s -> { System.out.println(s); });     OFYU     SFTVMU
  24. 'MPXBCMF ྫ֎ͷѻ͍ Flowable.just("1", "2", "three", “4") .map(Integer::parseInt)
 .subscribe(num -> {


    System.out.println(num);
 }
 , throwable -> {
 System.out.println("error : " + throwable.getMessage());
 });   FSSPS'PSJOQVUTUSJOHUISFF SFTVMU /VNCFS'PSNBU&YDFQUJPO Τϥʔऴྃ
  25. 'MPXBCMF ࣮ߦ5ISFBE੍ޚ Flowable.just("a", "b", "c", "d") .map(s -> { System.out.println(Thread.currentThread().getName()

    + " : " + s); return s.toUpperCase(); }) .subscribeOn(Schedulers.newThread()) .observeOn(Schedulers.computation()) .blockingSubscribe(s -> { System.out.println(Thread.currentThread().getName() + " : " + s); }); 3Y/FX5ISFBE4DIFEVMFSB 3Y/FX5ISFBE4DIFEVMFSC 3Y/FX5ISFBE4DIFEVMFSD 3Y/FX5ISFBE4DIFEVMFSE 3Y$PNQVUBUJPO5ISFBE1PPM" 3Y$PNQVUBUJPO5ISFBE1PPM# 3Y$PNQVUBUJPO5ISFBE1PPM$ 3Y$PNQVUBUJPO5ISFBE1PPM% SFTVMU TVCTDSJCF0O'MPXBCMF0CTFSWFCMFॲཧͷ࣮ߦεϨου PCTFSWF0OͦΕҎ߱ͷ࣮ߦεϨου ݩͷ'MPXBCMFͷ࣮ߦεϨουΛࢦఆ ͜͜Ҏ߱ͷ࣮ߦεϨουΛࢦఆ
  26. ม׵ॲཧ NBQ Flowable.just(1, 2, 3, 4) .map(num -> num *

    num)
 .subscribe(num -> {
 System.out.println(num);
 });     SFTVMU NBQ͸ετϦʔϜ಺ͷσʔλͦͷ΋ͷΛม׵͢Δ
  27. ม׵ॲཧ qBU.BQ Flowable.just(1, 2) .flatMap(v -> { // new flowable

    return Flowable.just(v, 2 * v); }) .subscribe(System.out::println);     SFTVMU qBU.BQ͸σʔλ͔Β'MPXBCMFΛ࡞੒ͯ͠ ࠷ऴతʹl'MPXBCMFΛऔΓ෷ͬͯzετϦʔϜΛߏங͢Δ " 'MPXBCMF " " # $ 'MPXBCMF # # 'MPXBCMF $ $ " # $ " # $
  28. ม׵ॲཧ qBU.BQ public Flowable<Integer> square(int v) { return Flowable.just(v).map(w ->

    w * w); } public Flowable<Integer> twin(int v) { return Flowable.just(v, v); }; Flowable<Integer> f1 = Flowable.just(1,2); Flowable<Integer> f2 = f1.flatMap(v -> square(v)); Flowable<Integer> f3 = f2.flatMap(v -> twin(v)); f1.subscribe(v1 -> System.out.println("f1 : " + v1)); f2.subscribe(v1 -> System.out.println("f2 : " + v1)); f3.subscribe(v1 -> System.out.println("f3 : " + v1)); G G G G G G G G SFTVMU 'MPXBCMF͸ʮ͋Δঢ়ଶʯͷσʔλετ ϦʔϜΛఆٛ͠ ม਺ͷΑ͏ʹѻ͑Δ
  29. w ετϦʔϜͷੜ੒ॲཧ KVTUGSPN$BMMBCMFGSPN"SSBZͳͲ w σʔλม׵ॲཧ pMUFSNBQqBU.BQͳͲ w ߹੒ॲཧ NFSHF[JQDPNCJOF-BUFTUͳͲ w

    ෭࡞༻ ߪಡऀ΁ͷ௨஌ͱ͸ผͷॲཧ  EP0O4VCTDSJCFEP0O/FYUEP0O$PNQMFUFͳͲ ΦϖϨʔλͷछผ ม׵ ੜ੒ TVCTDSJCF ߹੒ ෭࡞༻ ੜ੒ ม׵
  30. )PU$PME

  31. )PU$PMEͱ͍͏ੑ࣭ w ੜ࢈ऀ 'MPXBCMF0CTFSWBCMF ͷੑ࣭ w $PME͸ճ͝ͱͷར༻ ߪಡ͞Εͳ͍ͱՔಇͤͣɺߪಡ͝ͱʹ৽͍͠ετϦʔϜ͕࠶ੜ͞ΕΔ 'MPXBCMF0CTFSWBCMF͸େମ$PME ಈըͰݴ͏ͱ:PV5VCFͷ࠶ੜͷΑ͏ͳײ͡

    w )PU͸ܧଓతͳར༻ ετϦʔϜ͔Β஋ΛৗʹਨΕྲྀ͢ ෳ਺ͷߪಡऀʹಉ࣌ʹσʔλΛ௨஌͢Δ ಈըͰݴ͏ͱςϨϏͷΑ͏ͳײ͡
  32. 3Y+BWBͷ)PU$PME OFYU OFYU OFYU $PME 4VCTDSJCFS OFYU OFYU OFYU $PMEͷετϦʔϜ͸ߪಡऀ͝ͱʹ࠶౓࠶ੜ͞ΕΔΑ͏ͳΠϝʔδ

    4VCTDSJCFS
  33. 3Y+BWBͷ)PU$PME OFYU OFYU OFYU )PU )PUͷߪಡ͸ߪಡऀ͕ਨΕྲྀ͞ΕΔσʔλΛͦΕͧΕಡΉΠϝʔδ ਨΕྲྀ͠ 4VCTDSJCFS 4VCTDSJCFS

  34. )PUͳੜ࢈ऀ 1SPDFTTPS PublishProcessor<Integer> processor = PublishProcessor.create(); processor.subscribe(num -> { System.out.println("number1

    : " + num); }); processor.subscribe(num -> { System.out.println("number2 : " + num); }); processor.onNext(1); processor.onNext(2); processor.onNext(3); processor.onNext(4); OVNCFS OVNCFS OVNCFS OVNCFS OVNCFS OVNCFS OVNCFS OVNCFS SFTVMU ߪಡొ࿥ ෳ਺ొ࿥Մೳ σʔλొ࿥ 1SPDFTTPSʹ͸ड͚ޱ΋༻ҙ͞Ε͍ͯΔ
  35. ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ʹ͍ͭͯ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w

    ·ͱΊ
  36. ϢʔβʔΞΫγϣϯͰͷ׆༻ྫ RxTextView.textChanges(a1Text) .subscribe(e -> { b1Text.setText( “” + (Long.parseLong(e.text) +

    Long.parseLong(a2Text.getText()))); }); RxView.clicks(button) .debounce(1L, TimeUnit.SECONDS) .subscribe(x -> { // ੍ݶ͞Εͨೖྗ }) 3Y+BWBͷαϯϓϧͱͯ͠ग़ͯདྷΔ͕ ඞਢͱ͍͏Θ͚Ͱ΋ͳ͍ ݸਓతҙݟ
  37. "OESPJEͰ3Y+BWB͕ ࠷΋࢖ΘΕ͍Δ৔໘ ωοτϫʔΫ௨৴

  38. લఏͱͯ͠"OESPJEΞϓϦͷ੍ݶ w ϘλϯλοϓͰը໘ΛϩοΫ͠ͳ͍͜ͱ͕ਪ঑͞ΕΔ w ը໘ૢ࡞͸6*εϨου ϝΠϯεϨου ͰͷΈ࣮ࢪՄೳ w ωοτϫʔΫ௨৴͸6*εϨουʮҎ֎ʯͰ࣮ࢪՄೳ 6*5ISFBE

    *05ISFBE 7JFXߋ৽ "1*$BMM
  39. ඪ४ͷ"TZOD5BTL-PBEFSαϯϓϧ public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Bitmap> { //

    ActivityͷͲ͔͜ʹ͋ΔϘλϯλοϓίʔυ button.setOnClickListener(new OnSingleClickListener() {
 @Override
 public void onSingleClick(View view) {
 Bundle args = new Bundle(); args.putString("url", url); // ඇಉظॲཧΛґཔ getSupportLoaderManager().initLoader(0, args, this); } }); @Override public void Loader<Bitmap> onCreateLoader(int id, Bundle args) { return new ImageAsyncTaskLoader(this, args.getString("url")); } @Override public void onLoadFinished(Loader<Bitmap> arg0, Bitmap arg1) { imageView.setImageDrawable(new BitmapDrawable(getResources(), bmp)); } } Ϋϥογϡ͢ΔՄೳੑ͋Γ σʔλऔಘґཔ ݁Ռ$BMMCBDLΛड͚ͯ7JFXߋ৽
  40. "TZOD5BTLதʹ"DUJWJUZ͕ফ͑ڈΔ w ωοτϫʔΫ௨৴தʹผͷը໘͕ىಈ͢Δ - ϝϞϦ͕গͳ͍ͱόοΫάϥϯυͷActivity͸kill͞ΕΔ w ωοτϫʔΫ௨৴தʹը໘͕ճస͞ΕΔ - ը໘͕ճస͞ΕΔͱActivity͸࠶࡞੒͞ΕΔ w

    جຊతʹʮফ͑Δ͜ͱલఏʹ࡞Δʯͱ͍͏ελϯε
  41. "OESPJEΞϓϦͷωοτϫʔΫ௨৴ w ໰୊ - AsyncTaskॲཧͰ͸ਖ਼࣮͘͠૷͢Δίετ͕ߴ͍ - Callback੍ޚ͕ෳࡶʹͳΓ1 ActivityͰ࢖͑ΔAPIΛ૿΍͠ʹ͍͘ • ཧ૝తͳॲཧ

    - ࣮ߦεϨουͷ੍ޚΛ؆୯ʹߦ͍͍ͨ - Activityͷഁغ࣌ʹ͸ߋ৽ॲཧΛࢭΊ͍ͨ - ෳ਺ͷAPIΛݺͼग़͢৔߹ʹ΋͏·͘ॲཧ͍ͨ͠
  42. 3Y+BWB 3Y"OESPJE 3Y-JGFDZDMF

  43. 3Y+BWBͰ؆ܿʹهࡌ public class MainActivity extends RxActivity { // ActivityͷͲ͔͜ʹ͋ΔϘλϯλοϓίʔυ button.setOnClickListener(()

    -> {
 Flowable.fromCallable(() -> { return userModel.get(userId); }) .compose(bindToLifecycle()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(user -> { textView.setText(user.getName())); }); } } Ϣʔβʔ৘ใऔಘ "DUJWJUZ͕ഁغ͞ΕͨΒॲཧΛ΍ΊΔ 5ISFBE੍ޚ 7JFXߋ৽
  44. ࠶ར༻ͷͨΊʹ'MPXBCMFʹ͓͖͍ͯͨ͠ public class UserModel { public User get(String userId) {


    …
 } } public class UserModel { public Flowable<User> get(String userId) {
 …
 } } 'MPXBCMFϕʔεͷ໭Γ஋Λ࡞੒
  45. public class MainActivity extends RxActivity { button.setOnClickListener(() -> { userModel.get(userId)


    .flatMap(user -> imageMode.loadBitmap(user.getProfileUrl)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(bmp -> { imageView.setImageDrawable(new BitmapDrawable(getResources(), bmp)); }); } } ࠶ར༻ɿͭͷॲཧΛ߹੒ͯ݁͠ՌΛऔಘ ม׵࣌ʹՄಡੑ͕ߴ·Δ Ϣʔβʔ৘ใΛऔಘͯ͠ ϓϩϑΟʔϧը૾औಘ
  46. ࠶ར༻ɿҰׅऔಘ [JQ public class MainActivity extends RxActivity { button.setOnClickListener(() ->

    { Flowable.zip( userModel.get(userId), imageModel.get(url) )
 .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe((user, bmp) -> { textView.setText(user.name); imageView.setImageDrawable(new BitmapDrawable(getResources(), bmp)); }); } } ෳ਺ͷॲཧΛҰؾʹཁٻͯ͠ ݁Ռ͕ͦΖͬͨஈ֊Ͱ7JFXߋ৽
  47. ϦτϥΠ public class MainActivity extends RxActivity { button.setOnClickListener(() -> {

    userModel.get(userId)
 .flatMap(user -> imageMode.loadBitmap(this.user.profileUrl)) .retry(3, throwable -> { // retryՄ൱ίʔυ return true; }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(bmp -> { imageView.setImageDrawable(new BitmapDrawable(getResources(), bmp)); }); } } qBU.BQͨ͠ॲཧશମ͕Τϥʔ࣌࠶࣮ߦ͞ΕΔ
  48. 3Y+BWB͸ ෳ਺ͷը໘ͷҰׅߋ৽ʹ΋࢖ΘΕΔ

  49. ಉҰσʔλΛࢀর͢Δෳ਺ͷը໘ w ϝϞϦ͕͋Ε͹"DUJWJUZ͕ελοΫ͞Ε͍ͯͯ࢒͍ͬͯΔ w ΠϯελάϥϜͷz͍͍ͶzͳͲ͸ɺλοϓ͞Εͨॠؒʹશը ໘ʹσʔλΛ൓өͤ͞Δඞཁ͕͋Δ IUUQTTIPNBEBOFUXQDPOUFOUVQMPBETTJOHMF5BTLYKQH

  50. 1SPDFTTPSΛར༻ͨ͠ߋ৽Πϕϯτϋϒ w 1SPDFTTPSʹྲྀΕΔσʔλΛߪಡ͢Δ͜ͱͰෳ਺ͷ7JFXΛ ߋ৽ग़དྷΔ 1SPDFTTPS 7JFXߋ৽ 7JFXߋ৽ %BUB $IBOHF &WFOU

    PO/FYU TVCTDSJCF TVCTDSJCF
  51. w ͭલʹྲྀΕͨσʔλΛอ࣋͢Δ#FIBWJPS1SPDFTTPS w ྫ͑͹࠷৽ͷϩάΠϯϢʔβʔσʔλΛΩϟογϡ͓ͯ͘͠ ͳͲͷ࢖͍ํ͕ग़དྷΔ #FIBWJPS 1SPDFTTPS ৽ن7JFX 7JFXߋ৽ TVCTDSJCF

    TVCTDSJCF ࠷৽ͷ݅Λอ࣋ %BUB $IBOHF &WFOU PO/FYU ৽͘͠TVCTDSJCF͞Εͨ΋ͷʹΩϟογϡ͞Εͨ݅Λྲྀ͢ ༷ʑͳ1SPDFTTPS
  52. w "OESPJEಛ༗ͷ໰୊ʹΑΓωοτϫʔΫ௨৴Ͱඞཁ 3Y+BWBΛߴ౓ͳ1SPNJTFతʹར༻ w .PEFM૚ͷ໭Γ஋Λ'MPXBCMFԽ খ͞ͳॲཧΛ߹੒༷ͯ͠ʑͳॲཧΛੜΈग़͢ มߋͷଟ͍ϞόΠϧΞϓϦͰ͸ॏๅ͢Δ "OESPJEΞϓϦ։ൃͰͷ͔͍ͭͲ͜Ζ

  53. ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ʹ͍ͭͯ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w

    ·ͱΊ
  54. αʔόαΠυͰͷར༻Ҋ w ϚΠΫϩαʔϏεͰͷ"1*$BMM - ࣮ߦεϨου੍ޚ - Back PressureʹΑΔ੍ޚ - ෳ਺αʔϏεݺͼग़͠ͷ߹੒

    - ϦτϥΠͳͲͷ੍ޚ ϑϩϯτ޲͚"1* Ϣʔβʔ৘ใαʔϏε ը૾৘ใαʔϏε "1*$BMM "1*$BMM "1*$BMM Ґஔ৘ใαʔϏε
  55. 3FBDUJWF8FC1SPHSBNNJOH

  56. w Ϟσϧ૚ͷॲཧ %#ΞΫηεɺ"1*$BMM ΛετϦʔϜԽ w ίϯτϩʔϥͰϨεϙϯεΛੜ੒͢Δ࣌ʹϒϩοΩϯά͞ ΕΔ Ϟσϧ૚͚ͩϦΞΫςΟϒରԠʁ $POUSPMMFS ετϦʔϜ࡞੒

    CMPDLJOH4VCTDSJCF .PEFM CMPDLJOH SFRVFTU SFTQPOTF
  57. w ίϯτϩʔϥͰετϦʔϜΛߪಡ͠ͳ͍ͷͰϊϯϒϩοΩϯάͰॲཧՄೳ - ߴύϑΥʔϚϯε͕ظ଴Ͱ͖Δ - εϨουͷ༗ޮར༻͕ظ଴Ͱ͖Δ w )551ΫΤετͷड͚ޱʹ֤ͯσʔλͷੜ੒΍ग़ྗ·ͰͷzྲྀΕzΛ؆ܿʹ هड़ग़དྷΔ ίϯτϩʔϥ૚ͷϦΞΫςΟϒରԠ

    $POUSPMMFS ετϦʔϜ࡞੒ TVCTDSJCF .PEFM 'SBNFXPSL ετϦʔϜ࡞੒ ετϦʔϜ ߹੒ɾม׵
  58. 4QSJOH#PPUͰ࣮ݱՄೳ

  59. 4QSJOHͰ͸3FBDUPS͕࢖ΘΕΔ w 3YʹӨڹΛड͚ͨϦΞΫςΟϒϥΠϒϥϦ 3Y+BWBͱಉ͡ΦϖϨʔλ΋ଟ਺͋Γ w 3FBDUJWF4USFBNTʹ४ڌ 3Y+BWB 3FBDUPS ରԠ+BWBόʔδϣϯ +BWB

    +BWB 0CTFSWBCMFγʔέϯε 'MPXBCMF 'MVY εϨου੍ޚϝιου TVCTDSJCF0O
 PCTFSWF0O TVCTDSJCF0O QVCMJTI0O 3Y+BWBͱ3FBDUPSͰେ͖͘ҧ͏ͱ͜Ζ
  60. 4QSJOH8FC3FBDUJWFͷαϯϓϧ @GetMapping(value = "/github_user", produces = "application/json") public Flux<GithubUser> githubUser()

    { return httpGet("https://api.github.com/users?slice=1") .flatMapMany(response -> response.bodyToFlux(GithubUser.class)) .take(5); } public Mono<ClientResponse> httpGet(String url) { WebClient client = WebClient.create(url); return client.get().uri("").exchange(); } public class GithubUser { public String login; public String avatar_url; public String toString() { return "[login : " + login + ", avator_url : " + avatar_url + "]"; } } > curl http://localhost/github_user [{"login":"mojombo","avatar_url":"https://avatars3.githubusercontent.com/u/1?v=3"}, {"login":"defunkt","avatar_url":"https://avatars3.githubusercontent.com/u/2?v=3"}, {"login":"pjhyett","avatar_url":"https://avatars3.githubusercontent.com/u/3?v=3"}, {"login":"wycats","avatar_url":"https://avatars3.githubusercontent.com/u/4?v=3"}, {"login":"ezmobius","avatar_url":"https://avatars3.githubusercontent.com/u/5?v=3"}] SFTVMU 'MVYϕʔεͷϨεϙϯε 3FBDUJWF8FC$MJFOU
  61. ΋͔ͨ͠͠Βศརͳ࢖͍ํ w σʔλ഑৴੍ޚ - σʔλΛอ࣋͢ΔετϦʔϜ - λΠϛϯάΛ੍ޚ͢ΔΞΫγϣϯετϦʔϜ - 2ͭΛ෼͚ͯετϦʔϜԽͯ͠߹੒͢Δ͜ͱͰෳࡶͳ੍ޚΛ࣮ݱ σʔλετϦʔϜ

    ΞΫγϣϯετϦʔϜ ఆظ࣮ߦ΍ඇಉظΠϕϯτ ߹੒ [JQ DPNCJOF-BUFTU σʔλ഑৴੍ޚ
  62. [JQ w ̎ͭҎ্ ͭҎԼ ͷετϦʔϜΛʮ߹੒ʯ͢Δ w σʔλ͕ྲྀΕΔλΠϛϯά͸֤ετϦʔϜͷσʔλ͕ἧͬ ͨͱ͖ [JQ Y

    Z lz Y Z     " # $ " ߹੒݁Ռ # $
  63. " # $ DPNCJOF-BUFTU w ̎ͭҎ্ ͭҎԼ ͷετϦʔϜΛʮ߹੒ʯ͢Δ w σʔλྲྀΕΔλΠϛϯά͸ετϦʔϜͷͲΕ͔ʹz/FYUz͕ൃߦͨ͞ͱ͖

    w /FYU͕ൃߦ͞Εͳ͔ͬͨํ͸લճྲྀͨ͠σʔλ -BUFTU Λ࠶౓ྲྀ͢ DPNCJOF-BUFTU Y Z lz Y Z     " ߹੒݁Ռ # # $ $
  64. 4FSWFS4FOU&WFOUTͰ߹੒Λ࢖͏ @GetMapping(value = "/stream_data/", produces = "text/event-stream") public Flux<GithubUser> streamData()

    { Flux<Long> interval = Flux.interval(Duration.ofSeconds(1)); Flux<GithubUser> results = httpGet("https://api.github.com/users?slice=1") .flatMapMany(response -> response.bodyToFlux(GithubUser.class)) .take(5); return Flux.zip(interval, results) .map(Tuple2::getT2); } λΠϛϯάΛ͸͔Δ'MVY σʔλΛੜ੒͢Δ'MVY
  65. [JQͨ݁͠Ռ ඵ͝ͱʹ̍ߦ௥Ճ͞Ε͍ͯ͘

  66. ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w

    ·ͱΊ
  67. ࣮ࡍʹͲ͏΍ͬͯಋೖ͔ͨ͠ʁ w "OESPJEΞϓϦʹ೥Ҏ্લʹಋೖ w J04։ൃऀͰϦΞΫςΟϒϓϩάϥϛϯά࣮ફऀ͕νʔϜʹ δϣΠϯͨ͠ͷ͕͖͔͚ͬ w ޱ಄ʹΑΔઆ໌΍13ϨϏϡʔΛ௨ͯ͡νʔϜʹ఻ൖ w ઃܭʹ͍ͭͯ͸τϥΠΞϯυΤϥʔ

    Ұੲલ͸Ұॹʹٞ࿦ग़དྷΔਓ͕ډͳ͍ͱಋೖ͠ʹ͍͘ঢ়ଶͩͬͨ
  68. ࠓͳΒಠश͸ՄೳͰ͸ʁ w ʮ3Y+BWBϦΞΫςΟϒϓϩάϥϛϯάʯ͕ૉ੖Β͍͠ w ࣮ࡍʹखΛಈ͔༷ͯ͠ʑͳಈ࡞Λ֬ೝͯ͠ΈΔͷ͕ཧղ΁ͷۙಓ IUUQSYNBSCMFTDPN΋ࢀߟʹ w ઃܭ࿦ͳͲ΋೔ຊޠจݙ͕2JJUBʹͨ͘͞Μ্͕͍ͬͯΔ

  69. 3Y+BWBͰؾΛ͚ͭΔ͜ͱ w QVCMJDͳϝιουΛ'MPXBCMF0CTFSWBCMFʹґଘͤͨ͞৔ ߹ͷةݥੑ όʔδϣϯΞοϓ࣌ͷޙํޓ׵ੑͷةݥੑ ଞͷϑϨʔϜϫʔΫ΁ͷ৐Γ׵͑ΒΕͳ͍ةݥੑ

  70. $PODMVTJPO w 3Y+BWB͸ඇಉظͳσʔλετϦʔϜΛॲཧ͢ΔϥΠϒϥϦɻεϨου੍ޚ͕ಛ ௃తͰؔ਺ܕతͳΦϖϨʔλΛଟ࣋ͭ͘ w 3Y+BWBͷ࢖͍ॴɿ"OESPJEΞϓϦͷͷωοτϫʔΫ௨৴ॲཧΛ؆ܿʹهड़ग़དྷ Δ w 8FCϓϩάϥϛϯάʹ͓͍ͯ΋ϦΞΫςΟϒϓϩάϥϛϯά͸ॏཁ౓Λ૿ͯ͠ ͖ͦ͏

    w "OESPJEΞϓϦ։ൃҎ֎ͳΒ3FBDUPS͕ྑ͍બ୒ࢶͰ͸ ͨͩ͠೔ຊޠจݙͷଟ͔͞Β3Y+BWBͰษڧ͓ͯ͘͠ͱ͍͏ͷ΋ΞϦͰ͸
  71. ϦΞΫςΟϒϓϩάϥϛϯάͰ ͖ͬͱϓϩάϥϛϯά͕ ΋ͬͱָ͘͠ͳΔ͸ͣʂ

  72. ॕ"OESPJEͰ,PUMJO͕ਖ਼ࣜαϙʔτʂʂ w 3Y+BWB͸,PUMJOͰ΋࢖͑Δ w 3Y,PUMJO΋͋Δ val list = listOf("Alpha", "Beta",

    "Gamma", "Delta", "Epsilon") list.toObservable() // extension function for Iterables
  73. ࢀߟจݙ w IUUQOJOKJOLVOIBUFOBCMPHDPNFOUSZJOUSPSYKB ʲ຋༁ʳ͋ͳ͕ͨٻΊ͍ͯͨϦΞΫςΟϒϓϩάϥϛϯάೖ໳ w IUUQPLBQJFTIBUFCMPKQFOUSZ ؔ਺ܕϓϩάϥϚͷͨΊͷ3Yೖ໳ w IUUQRJJUBDPNZVZB@QSFTUPJUFNTGBEEDGD 3Y+BWBʹ೔Ͱೖ໳͠ɺ"OESPJEΞϓϦͷϦετૢ࡞ɺඇಉظॲཧɺมߋ௨஌ͷ՝୊Λղܾͨ͠࿩

    w IUUQTCMPHJLBNFOUSJFT 3Y+BWBϦΞΫςΟϒϓϩάϥϛϯάʯ͸4QSJOH3FBDUPSΛษڧ͢Δͷʹ΋໾ʹཱͭॻ੶ w IUUQTHJUIVCDPNKZVLVUZPTQSJOHSFBDUJWFFYBNQMF