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.8k
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
520
モバイルアプリでHTTP/2
nmorioka
1
130
既存AndroidアプリでKotlin導入を考える
nmorioka
0
98
Cardbord SDK
nmorioka
0
88
AndroidでJava8
nmorioka
0
280
Other Decks in Technology
See All in Technology
サイバー攻撃を想定したセキュリティガイドライン 策定とASM及びCNAPPの活用方法
syoshie
3
1.3k
Jetpack Composeで始めるServer Cache State
ogaclejapan
2
170
Oracle Cloudの生成AIサービスって実際どこまで使えるの? エンジニア目線で試してみた
minorun365
PRO
4
280
ずっと昔に Star をつけたはずの思い出せない GitHub リポジトリを見つけたい!
rokuosan
0
150
PHPからGoへのマイグレーション for DMMアフィリエイト
yabakokobayashi
1
170
サービスでLLMを採用したばっかりに振り回され続けたこの一年のあれやこれや
segavvy
2
410
Opcodeを読んでいたら何故かphp-srcを読んでいた話
murashotaro
0
230
re:Invent をおうちで楽しんでみた ~CloudWatch のオブザーバビリティ機能がスゴい!/ Enjoyed AWS re:Invent from Home and CloudWatch Observability Feature is Amazing!
yuj1osm
0
120
KubeCon NA 2024 Recap / Running WebAssembly (Wasm) Workloads Side-by-Side with Container Workloads
z63d
1
250
オプトインカメラ:UWB測位を応用したオプトイン型のカメラ計測
matthewlujp
0
170
生成AIのガバナンスの全体像と現実解
fnifni
1
190
Amazon Kendra GenAI Index 登場でどう変わる? 評価から学ぶ最適なRAG構成
naoki_0531
0
110
Featured
See All Featured
Keith and Marios Guide to Fast Websites
keithpitt
410
22k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
GitHub's CSS Performance
jonrohan
1030
460k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
48
2.2k
Designing for humans not robots
tammielis
250
25k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
Producing Creativity
orderedlist
PRO
341
39k
Scaling GitHub
holman
458
140k
How To Stay Up To Date on Web Technology
chriscoyier
789
250k
Building Your Own Lightsaber
phodgson
103
6.1k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
28
4.4k
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