Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Androidアプリ開発からみた RxJavaの使いどころ
Search
Naoki Morioka
May 16, 2017
Technology
1
3.9k
Androidアプリ開発からみた RxJavaの使いどころ
JJUG CCC 2017 Spring #ccc_i3
Naoki Morioka
May 16, 2017
Tweet
Share
More Decks by Naoki Morioka
See All by Naoki Morioka
10年運用している 画像サービスでのJavaの活用と 今後の展望
nmorioka
0
560
モバイルアプリでHTTP/2
nmorioka
1
130
既存AndroidアプリでKotlin導入を考える
nmorioka
0
110
Cardbord SDK
nmorioka
0
89
AndroidでJava8
nmorioka
0
300
Other Decks in Technology
See All in Technology
データ基盤からデータベースまで?広がるユースケースのDatabricksについて教えるよ!
akuwano
3
140
Delta airlines Customer®️ USA Contact Numbers: Complete 2025 Support Guide
deltahelp
0
930
[SRE NEXT] ARR150億円_エンジニア140名_27チーム_17プロダクトから始めるSLO.pdf
satos
2
650
AWS CDK 開発を成功に導くトラブルシューティングガイド
wandora58
3
130
IPA&AWSダブル全冠が明かす、人生を変えた勉強法のすべて
iwamot
PRO
2
190
ABEMAの本番環境負荷試験への挑戦
mk2taiga
4
310
オフィスビルを監視しよう:フィジカル×デジタルにまたがるSLI/SLO設計と運用の難しさ / Monitoring Office Buildings: The Challenge of Physical-Digital SLI/SLO Design & Operation
bitkey
1
120
United Airlines Customer Service– Call 1-833-341-3142 Now!
airhelp
0
170
20250705 Headlamp: 專注可擴展性的 Kubernetes 用戶界面
pichuang
0
290
VGGT: Visual Geometry Grounded Transformer
peisuke
1
200
開発生産性を組織全体の「生産性」へ! 部門間連携の壁を越える実践的ステップ
sudo5in5k
3
7.5k
衛星運用をソフトウェアエンジニアに依頼したときにできあがるもの
sankichi92
1
160
Featured
See All Featured
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
Testing 201, or: Great Expectations
jmmastey
43
7.6k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.7k
Code Reviewing Like a Champion
maltzj
524
40k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
20
1.3k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
Producing Creativity
orderedlist
PRO
346
40k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Docker and Python
trallard
44
3.5k
How GitHub (no longer) Works
holman
314
140k
Embracing the Ebb and Flow
colly
86
4.7k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
30
2.1k
Transcript
"OESPJEΞϓϦ։ൃ͔ΒΈͨ 3Y+BWBͷ͍Ͳ͜Ζ ++6($$$4QSJOH /BPLJ.PSJPLB
ΤϯδχΞྺ $ݴޠΛ΄Ͳɺޙ΄ͱΜͲ+BWB ࠷ۙ"OEPSJEJ04ΞϓϦ։ൃ Ԭঘه !O@NPSJPLB IUUQTHJUIVCDPNONPSJPLB "CPVU.F ϑϦϡʔגࣜձࣾۈژࡏॅ
ࢲͷ3Y+BWBͷϞνϕʔγϣϯ w ؔܕzతzͳॲཧͷѻ͍͕Մೳ খ͍͞ॲཧΛΈ߹Θͤͯେ͖ͳॲཧΛهड़͍ͯ͘͠ +BWBͰهड़ग़དྷͯ΄Ͳྑ͍όϥϯεײ֮ w ͬͯΈΔͱ৭ʑͱ৽͍͠ൃݟ͕͋Δ qBU.BQ[JQDPNCJOF-BUFTUͳͲͷར༻
ར༻͍ͯ͠Δόʔδϣϯ w +%,@ w 3Y+BWB w 4QSJOH#PPU#6*-%4/"14)05 w 3FBDUPSɿ#6*-%4/"14)05
ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ʹ͍ͭͯ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w
·ͱΊ
w +BWB7.্Ͱಈ࡞͢Δ؍ଌՄೳ 0CTFSWBCMF ͳ࣌ܥྻσʔλ Λ༻͍ͨɺඇಉظͳΠϕϯτϕʔεͷϓϩάϥϛϯά ϦΞΫςΟ ϒϓϩάϥϛϯά ΛՄೳʹ͢ΔϥΠϒϥϦ w +BWBҎ্Ͱར༻Մೳ
w ݱঢ়ͷϝΠϯ3Y+BWBܥ w 3Y+BWB3FBDUJWF&YUFOTJPOT 3FBDUJWF4USFBNT 8IBU`T3Y+BWBʁ
ϦΞΫςΟϒϓϩάϥϛϯάᶃ w ͋ΔσʔλετϦʔϜʹରͯ͠ ͍ͭ͘Δ͔Θ͔Βͳ͍ σʔ λʹԠతʹϓϩάϥϛϯάΛߦ͏͜ͱ σʔλ ࣌ܥྻʹԊͬͨྲྀΕετϦʔϜ σʔλ ʜ
ϦΞΫςΟϒϓϩάϥϛϯάᶄ w 3Y+BWBʹ͓͍ͯ+BWBΠϯελϯεͷ͕ͭͭσʔλ 4USFBN"1*ͱಉ͡ " # $ 4USJOHσʔλ " "
" # $ # # $ $ # $ " # $ " # $ -JTUσʔλ
ϦΞΫςΟϒϓϩάϥϛϯάᶅ w σʔλετϦʔϜͷੜɺมɺ߹Λߦ͏ w ετϦʔϜ͔ΒདྷΔσʔλΛड͚औͬͨॲཧ ߪಡ Λهࡌ͢Δ " # $
Πϕϯτ " " Πϕϯτ ʜ B C D B B 4USJOH ͂ TUP-PXFS$BTF ม 4ZTUFNPVUQSJOUMO ߪಡ B C D ʜ
w ϚΠΫϩιϑτࣾʹΑͬͯఏএ͞ΕͨɺෳࡶͳඇಉظॲཧΠϕ ϯτॲཧɺ͕࣌ؒؔ͢ΔॲཧͳͲΛهड़Ͱ͖Δ"1*܊ͷ༷ w /&5+4ͳͲ֤छ࣮͕͋Δ w େ͖͍༷ 3FBDUJWF&YUFOTJPOT 3Y IUUQTHJUIVCDPN3FBDUJWF&YUFOTJPOT
w ϊϯϒϩοΩϯάͳ#BDL1SFTTVSFΛ༻͍ͨඇಉظετϦʔϜॲཧͷ༷ w ͭͷΠϯλʔϑΣʔεఆٛͷఏڙ 1VCMJTIFS 4VCTDSJCFS 4VCTDSJQUJPO 1SPDFTTPS w 5FTU4VJUFͷఏڙ
5$, w খ͍༷͞ 3FBDUJWF4USFBNT
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> { }
#BDL1SFTTVSF w ड৴ଆ͔Βૹ৴ଆͷσʔλϑϩʔ੍ޚ w ॲཧ͕ऴΘͬͨ͜ͱΛ͑ͯ࣍ͷσʔλΛऔಘ͢Δ w ૹ৴ଆͷσʔλੜͷํ͕͍߹4USBUFHZʹैͬͨॲཧ࣮ࢪ w ࿈݁߹Մೳ ॲཧ͖ͬͨ͠ͷͰ࣍Լ͍͞
data 0, #BDL1SFTTVSF 4USBUFHZ #6''&3 %301 -"5&45 &3303 /0/& Publisher Subscriber
ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ʹ͍ͭͯ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w
·ͱΊ
3Y+BWBͷίΞ 'MPXBCMF0CTFSWBCMF
'MPXBCMF0CTFSWBCMFͱԿ͔ʁ w σʔλͷετϦʔϜΛੜ࢈ͯ͠ɺอ࣋͢ΔೖΕͷΑ͏ͳͷɻ ߪಡ TVCTDSJCF Մೳ 'MPXBCMF1VCMJTIFSΛ࣮ɺ#BDL1SFTTVSF੍ޚ͋Γɹ 0CTFSWBCMF#BDL1SFTTVSF੍ޚͳ͠ɻύϑΥʔϚϯεྑ͍ w ͭͷঢ়ଶΛߪಡऀʹ͑Δɹ
4VCTDSJCF/FYU$PNQMFUF&SSPS w ͭͷੑ࣭Λ࣋ͭ )PU $PME
̐ͭͷঢ়ଶ w 4VCTDSJCF௨ͷ४උ͕ग़དྷͨঢ়ଶ w /FYUσʔλ͕ྲྀΕ͍ͯΔঢ়ଶɻσʔλ༰͕ϋϯυϦϯά͞ΕΔ w $PNQMFUFਖ਼ৗऴྃɻετϦʔϜʹσʔλ͕ྲྀΕͳ͘ͳΔ w &SSPSҟৗऴྃɻετϦʔϜʹσʔλྲྀΕͳ͘ͳΔ OFYU
OFYU OFYU OFYU OFYU DPNQMFUF OFYU OFYU FSSPS TVCTDSJCF TVCTDSJCF
ߪಡॲཧ 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 ੜ ᶃ։࢝ ᶄσʔλऔಘ ᶅਖ਼ৗऴྃ
ߪಡॲཧ ؔܕ*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ॲཧϋϯυϦϯά Τϥʔॲཧ
ߪಡॲཧ ؔܕ*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Λ࡞ͯ͠ॲཧ͍ͯ͠Δ
'MPXBCMFͱ+BWB4USFBN"1*ͱͷҧ͍ w 'MPXBCMF࠶ར༻Մೳ w 'MPXBCMF࣮ߦ5ISFBEΛॲཧ్தͰΓସ͑Մೳ w ྫ֎ͷѻ͍ 4USFBN"1*֎ଆʹൖ͢Δ 'MPXBCMF෦Ͱॲཧ͢Δ͜ͱ͕Մೳ
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
'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
'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 Τϥʔऴྃ
'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ͷ࣮ߦεϨουΛࢦఆ ͜͜Ҏ߱ͷ࣮ߦεϨουΛࢦఆ
มॲཧ NBQ Flowable.just(1, 2, 3, 4) .map(num -> num *
num) .subscribe(num -> { System.out.println(num); }); SFTVMU NBQετϦʔϜͷσʔλͦͷͷΛม͢Δ
มॲཧ 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 $ $ " # $ " # $
มॲཧ 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ʮ͋Δঢ়ଶʯͷσʔλετ ϦʔϜΛఆٛ͠ มͷΑ͏ʹѻ͑Δ
w ετϦʔϜͷੜॲཧ KVTUGSPN$BMMBCMFGSPN"SSBZͳͲ w σʔλมॲཧ pMUFSNBQqBU.BQͳͲ w ߹ॲཧ NFSHF[JQDPNCJOF-BUFTUͳͲ w
෭࡞༻ ߪಡऀͷ௨ͱผͷॲཧ EP0O4VCTDSJCFEP0O/FYUEP0O$PNQMFUFͳͲ ΦϖϨʔλͷछผ ม ੜ TVCTDSJCF ߹ ෭࡞༻ ੜ ม
)PU$PME
)PU$PMEͱ͍͏ੑ࣭ w ੜ࢈ऀ 'MPXBCMF0CTFSWBCMF ͷੑ࣭ w $PMEճ͝ͱͷར༻ ߪಡ͞Εͳ͍ͱՔಇͤͣɺߪಡ͝ͱʹ৽͍͠ετϦʔϜ͕࠶ੜ͞ΕΔ 'MPXBCMF0CTFSWBCMFେମ$PME ಈըͰݴ͏ͱ:PV5VCFͷ࠶ੜͷΑ͏ͳײ͡
w )PUܧଓతͳར༻ ετϦʔϜ͔ΒΛৗʹਨΕྲྀ͢ ෳͷߪಡऀʹಉ࣌ʹσʔλΛ௨͢Δ ಈըͰݴ͏ͱςϨϏͷΑ͏ͳײ͡
3Y+BWBͷ)PU$PME OFYU OFYU OFYU $PME 4VCTDSJCFS OFYU OFYU OFYU $PMEͷετϦʔϜߪಡऀ͝ͱʹ࠶࠶ੜ͞ΕΔΑ͏ͳΠϝʔδ
4VCTDSJCFS
3Y+BWBͷ)PU$PME OFYU OFYU OFYU )PU )PUͷߪಡߪಡऀ͕ਨΕྲྀ͞ΕΔσʔλΛͦΕͧΕಡΉΠϝʔδ ਨΕྲྀ͠ 4VCTDSJCFS 4VCTDSJCFS
)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ʹड͚ޱ༻ҙ͞Ε͍ͯΔ
ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ʹ͍ͭͯ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w
·ͱΊ
ϢʔβʔΞΫγϣϯͰͷ׆༻ྫ 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ͷαϯϓϧͱͯ͠ग़ͯདྷΔ͕ ඞਢͱ͍͏Θ͚Ͱͳ͍ ݸਓతҙݟ
"OESPJEͰ3Y+BWB͕ ࠷ΘΕ͍Δ໘ ωοτϫʔΫ௨৴
લఏͱͯ͠"OESPJEΞϓϦͷ੍ݶ w ϘλϯλοϓͰը໘ΛϩοΫ͠ͳ͍͜ͱ͕ਪ͞ΕΔ w ը໘ૢ࡞6*εϨου ϝΠϯεϨου ͰͷΈ࣮ࢪՄೳ w ωοτϫʔΫ௨৴6*εϨουʮҎ֎ʯͰ࣮ࢪՄೳ 6*5ISFBE
*05ISFBE 7JFXߋ৽ "1*$BMM
ඪ४ͷ"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ߋ৽
"TZOD5BTLதʹ"DUJWJUZ͕ফ͑ڈΔ w ωοτϫʔΫ௨৴தʹผͷը໘͕ىಈ͢Δ - ϝϞϦ͕গͳ͍ͱόοΫάϥϯυͷActivitykill͞ΕΔ w ωοτϫʔΫ௨৴தʹը໘͕ճస͞ΕΔ - ը໘͕ճస͞ΕΔͱActivity࠶࡞͞ΕΔ w
جຊతʹʮফ͑Δ͜ͱલఏʹ࡞Δʯͱ͍͏ελϯε
"OESPJEΞϓϦͷωοτϫʔΫ௨৴ w - AsyncTaskॲཧͰਖ਼࣮͘͢͠Δίετ͕ߴ͍ - Callback੍ޚ͕ෳࡶʹͳΓ1 ActivityͰ͑ΔAPIΛ૿͠ʹ͍͘ • ཧతͳॲཧ
- ࣮ߦεϨουͷ੍ޚΛ؆୯ʹߦ͍͍ͨ - Activityͷഁغ࣌ʹߋ৽ॲཧΛࢭΊ͍ͨ - ෳͷAPIΛݺͼग़͢߹ʹ͏·͘ॲཧ͍ͨ͠
3Y+BWB 3Y"OESPJE 3Y-JGFDZDMF
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ߋ৽
࠶ར༻ͷͨΊʹ'MPXBCMFʹ͓͖͍ͯͨ͠ public class UserModel { public User get(String userId) {
… } } public class UserModel { public Flowable<User> get(String userId) { … } } 'MPXBCMFϕʔεͷΓΛ࡞
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)); }); } } ࠶ར༻ɿͭͷॲཧΛ߹ͯ݁͠ՌΛऔಘ ม࣌ʹՄಡੑ͕ߴ·Δ ϢʔβʔใΛऔಘͯ͠ ϓϩϑΟʔϧը૾औಘ
࠶ར༻ɿҰׅऔಘ [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ߋ৽
ϦτϥΠ 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ͨ͠ॲཧશମ͕Τϥʔ࣌࠶࣮ߦ͞ΕΔ
3Y+BWB ෳͷը໘ͷҰׅߋ৽ʹΘΕΔ
ಉҰσʔλΛࢀর͢Δෳͷը໘ w ϝϞϦ͕͋Ε"DUJWJUZ͕ελοΫ͞Ε͍͍ͯͯͬͯΔ w ΠϯελάϥϜͷz͍͍ͶzͳͲɺλοϓ͞Εͨॠؒʹશը ໘ʹσʔλΛөͤ͞Δඞཁ͕͋Δ IUUQTTIPNBEBOFUXQDPOUFOUVQMPBETTJOHMF5BTLYKQH
1SPDFTTPSΛར༻ͨ͠ߋ৽Πϕϯτϋϒ w 1SPDFTTPSʹྲྀΕΔσʔλΛߪಡ͢Δ͜ͱͰෳͷ7JFXΛ ߋ৽ग़དྷΔ 1SPDFTTPS 7JFXߋ৽ 7JFXߋ৽ %BUB $IBOHF &WFOU
PO/FYU TVCTDSJCF TVCTDSJCF
w ͭલʹྲྀΕͨσʔλΛอ࣋͢Δ#FIBWJPS1SPDFTTPS w ྫ͑࠷৽ͷϩάΠϯϢʔβʔσʔλΛΩϟογϡ͓ͯ͘͠ ͳͲͷ͍ํ͕ग़དྷΔ #FIBWJPS 1SPDFTTPS ৽ن7JFX 7JFXߋ৽ TVCTDSJCF
TVCTDSJCF ࠷৽ͷ݅Λอ࣋ %BUB $IBOHF &WFOU PO/FYU ৽͘͠TVCTDSJCF͞ΕͨͷʹΩϟογϡ͞Εͨ݅Λྲྀ͢ ༷ʑͳ1SPDFTTPS
w "OESPJEಛ༗ͷʹΑΓωοτϫʔΫ௨৴Ͱඞཁ 3Y+BWBΛߴͳ1SPNJTFతʹར༻ w .PEFMͷΓΛ'MPXBCMFԽ খ͞ͳॲཧΛ߹༷ͯ͠ʑͳॲཧΛੜΈग़͢ มߋͷଟ͍ϞόΠϧΞϓϦͰॏๅ͢Δ "OESPJEΞϓϦ։ൃͰͷ͔͍ͭͲ͜Ζ
ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ʹ͍ͭͯ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w
·ͱΊ
αʔόαΠυͰͷར༻Ҋ w ϚΠΫϩαʔϏεͰͷ"1*$BMM - ࣮ߦεϨου੍ޚ - Back PressureʹΑΔ੍ޚ - ෳαʔϏεݺͼग़͠ͷ߹
- ϦτϥΠͳͲͷ੍ޚ ϑϩϯτ͚"1* ϢʔβʔใαʔϏε ը૾ใαʔϏε "1*$BMM "1*$BMM "1*$BMM ҐஔใαʔϏε
3FBDUJWF8FC1SPHSBNNJOH
w Ϟσϧͷॲཧ %#ΞΫηεɺ"1*$BMM ΛετϦʔϜԽ w ίϯτϩʔϥͰϨεϙϯεΛੜ͢Δ࣌ʹϒϩοΩϯά͞ ΕΔ Ϟσϧ͚ͩϦΞΫςΟϒରԠʁ $POUSPMMFS ετϦʔϜ࡞
CMPDLJOH4VCTDSJCF .PEFM CMPDLJOH SFRVFTU SFTQPOTF
w ίϯτϩʔϥͰετϦʔϜΛߪಡ͠ͳ͍ͷͰϊϯϒϩοΩϯάͰॲཧՄೳ - ߴύϑΥʔϚϯε͕ظͰ͖Δ - εϨουͷ༗ޮར༻͕ظͰ͖Δ w )551ΫΤετͷड͚ޱʹ֤ͯσʔλͷੜग़ྗ·ͰͷzྲྀΕzΛ؆ܿʹ هड़ग़དྷΔ ίϯτϩʔϥͷϦΞΫςΟϒରԠ
$POUSPMMFS ετϦʔϜ࡞ TVCTDSJCF .PEFM 'SBNFXPSL ετϦʔϜ࡞ ετϦʔϜ ߹ɾม
4QSJOH#PPUͰ࣮ݱՄೳ
4QSJOHͰ3FBDUPS͕ΘΕΔ w 3YʹӨڹΛड͚ͨϦΞΫςΟϒϥΠϒϥϦ 3Y+BWBͱಉ͡ΦϖϨʔλଟ͋Γ w 3FBDUJWF4USFBNTʹ४ڌ 3Y+BWB 3FBDUPS ରԠ+BWBόʔδϣϯ +BWB
+BWB 0CTFSWBCMFγʔέϯε 'MPXBCMF 'MVY εϨου੍ޚϝιου TVCTDSJCF0O PCTFSWF0O TVCTDSJCF0O QVCMJTI0O 3Y+BWBͱ3FBDUPSͰେ͖͘ҧ͏ͱ͜Ζ
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
͔ͨ͠͠Βศརͳ͍ํ w σʔλ৴੍ޚ - σʔλΛอ࣋͢ΔετϦʔϜ - λΠϛϯάΛ੍ޚ͢ΔΞΫγϣϯετϦʔϜ - 2ͭΛ͚ͯετϦʔϜԽͯ͠߹͢Δ͜ͱͰෳࡶͳ੍ޚΛ࣮ݱ σʔλετϦʔϜ
ΞΫγϣϯετϦʔϜ ఆظ࣮ߦඇಉظΠϕϯτ ߹ [JQ DPNCJOF-BUFTU σʔλ৴੍ޚ
[JQ w ̎ͭҎ্ ͭҎԼ ͷετϦʔϜΛʮ߹ʯ͢Δ w σʔλ͕ྲྀΕΔλΠϛϯά֤ετϦʔϜͷσʔλ͕ἧͬ ͨͱ͖ [JQ Y
Z lz Y Z " # $ " ߹݁Ռ # $
" # $ DPNCJOF-BUFTU w ̎ͭҎ্ ͭҎԼ ͷετϦʔϜΛʮ߹ʯ͢Δ w σʔλྲྀΕΔλΠϛϯάετϦʔϜͷͲΕ͔ʹz/FYUz͕ൃߦͨ͞ͱ͖
w /FYU͕ൃߦ͞Εͳ͔ͬͨํલճྲྀͨ͠σʔλ -BUFTU Λ࠶ྲྀ͢ DPNCJOF-BUFTU Y Z lz Y Z " ߹݁Ռ # # $ $
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
[JQͨ݁͠Ռ ඵ͝ͱʹ̍ߦՃ͞Ε͍ͯ͘
ΞδΣϯμ w 3Y+BWBͷ֓ཁ w 3Y+BWBͷجຊ w "OESPJEΞϓϦͰͷར༻ w αʔόαΠυͰͷར༻ʹ͍ͭͯ w
·ͱΊ
࣮ࡍʹͲ͏ͬͯಋೖ͔ͨ͠ʁ w "OESPJEΞϓϦʹҎ্લʹಋೖ w J04։ൃऀͰϦΞΫςΟϒϓϩάϥϛϯά࣮ફऀ͕νʔϜʹ δϣΠϯͨ͠ͷ͕͖͔͚ͬ w ޱ಄ʹΑΔઆ໌13ϨϏϡʔΛ௨ͯ͡νʔϜʹൖ w ઃܭʹ͍ͭͯτϥΠΞϯυΤϥʔ
ҰੲલҰॹʹٞग़དྷΔਓ͕ډͳ͍ͱಋೖ͠ʹ͍͘ঢ়ଶͩͬͨ
ࠓͳΒಠशՄೳͰʁ w ʮ3Y+BWBϦΞΫςΟϒϓϩάϥϛϯάʯ͕ૉΒ͍͠ w ࣮ࡍʹखΛಈ͔༷ͯ͠ʑͳಈ࡞Λ֬ೝͯ͠ΈΔͷ͕ཧղͷۙಓ IUUQSYNBSCMFTDPNࢀߟʹ w ઃܭͳͲຊޠจݙ͕2JJUBʹͨ͘͞Μ্͕͍ͬͯΔ
3Y+BWBͰؾΛ͚ͭΔ͜ͱ w QVCMJDͳϝιουΛ'MPXBCMF0CTFSWBCMFʹґଘͤͨ͞ ߹ͷةݥੑ όʔδϣϯΞοϓ࣌ͷޙํޓੑͷةݥੑ ଞͷϑϨʔϜϫʔΫͷΓ͑ΒΕͳ͍ةݥੑ
$PODMVTJPO w 3Y+BWBඇಉظͳσʔλετϦʔϜΛॲཧ͢ΔϥΠϒϥϦɻεϨου੍ޚ͕ಛ తͰؔܕతͳΦϖϨʔλΛଟ࣋ͭ͘ w 3Y+BWBͷ͍ॴɿ"OESPJEΞϓϦͷͷωοτϫʔΫ௨৴ॲཧΛ؆ܿʹهड़ग़དྷ Δ w 8FCϓϩάϥϛϯάʹ͓͍ͯϦΞΫςΟϒϓϩάϥϛϯάॏཁΛ૿ͯ͠ ͖ͦ͏
w "OESPJEΞϓϦ։ൃҎ֎ͳΒ3FBDUPS͕ྑ͍બࢶͰ ͨͩ͠ຊޠจݙͷଟ͔͞Β3Y+BWBͰษڧ͓ͯ͘͠ͱ͍͏ͷΞϦͰ
ϦΞΫςΟϒϓϩάϥϛϯάͰ ͖ͬͱϓϩάϥϛϯά͕ ͬͱָ͘͠ͳΔͣʂ
ॕ"OESPJEͰ,PUMJO͕ਖ਼ࣜαϙʔτʂʂ w 3Y+BWB,PUMJOͰ͑Δ w 3Y,PUMJO͋Δ val list = listOf("Alpha", "Beta",
"Gamma", "Delta", "Epsilon") list.toObservable() // extension function for Iterables
ࢀߟจݙ w IUUQOJOKJOLVOIBUFOBCMPHDPNFOUSZJOUSPSYKB ʲ༁ʳ͋ͳ͕ͨٻΊ͍ͯͨϦΞΫςΟϒϓϩάϥϛϯάೖ w IUUQPLBQJFTIBUFCMPKQFOUSZ ؔܕϓϩάϥϚͷͨΊͷ3Yೖ w IUUQRJJUBDPNZVZB@QSFTUPJUFNTGBEEDGD 3Y+BWBʹͰೖ͠ɺ"OESPJEΞϓϦͷϦετૢ࡞ɺඇಉظॲཧɺมߋ௨ͷ՝Λղܾͨ͠
w IUUQTCMPHJLBNFOUSJFT 3Y+BWBϦΞΫςΟϒϓϩάϥϛϯάʯ4QSJOH3FBDUPSΛษڧ͢Δͷʹʹཱͭॻ੶ w IUUQTHJUIVCDPNKZVLVUZPTQSJOHSFBDUJWFFYBNQMF