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
Trip into the async world @ NYC Kotlin Meetup
Search
Roberto Orgiu
October 16, 2019
Programming
120
0
Share
Trip into the async world @ NYC Kotlin Meetup
These are the slides of my talk from NYC Kotlin Meetup @ Dropbox
Roberto Orgiu
October 16, 2019
More Decks by Roberto Orgiu
See All by Roberto Orgiu
Wellness & Droid
tiwiz
0
130
Behind the curtains
tiwiz
0
71
The Importance of Being Tested
tiwiz
0
420
An Android Dev start to Kotlin MPP
tiwiz
0
190
Fantastic API and where to find them
tiwiz
0
82
Flipping the Koin @ GDG Dev Party
tiwiz
1
76
Flipping the Koin
tiwiz
2
170
Trip into the async world
tiwiz
1
150
GraphQL IRL (Android Makers)
tiwiz
0
160
Other Decks in Programming
See All in Programming
実践CRDT
tamadeveloper
0
230
「効かない!」依存性注入(DI)を活用したAPI Platformのエラーハンドリング奮闘記
mkmk884
0
300
The free-lunch guide to idea circularity
hollycummins
0
420
Laravel Nightwatchの裏側 - Laravel公式Observabilityツールを支える設計と実装
avosalmon
1
320
アーキテクチャモダナイゼーションとは何か
nwiizo
17
4.2k
モックわからないマン卒業記 ~振る舞いを起点に見直した、フロントエンドテストにおけるモックの使いどころ~
tasukuwatanabe
3
440
20260320登壇資料
pharct
0
160
脱 雰囲気実装!AgentCoreを良い感じにWEBアプリケーションに組み込むために
takuyay0ne
3
440
テレメトリーシグナルが導くパフォーマンス最適化 / Performance Optimization Driven by Telemetry Signals
seike460
PRO
2
220
Symfonyの特性(設計思想)を手軽に活かす特性(trait)
ickx
0
130
Xdebug と IDE による デバッグ実行の仕組みを見る / Exploring-How-Debugging-Works-with-Xdebug-and-an-IDE
shin1x1
0
340
条件判定に名前、つけてますか? #phperkaigi #c
77web
2
970
Featured
See All Featured
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.2k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
61
43k
Code Reviewing Like a Champion
maltzj
528
40k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
99
Measuring & Analyzing Core Web Vitals
bluesmoon
9
800
We Have a Design System, Now What?
morganepeng
55
8.1k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Optimising Largest Contentful Paint
csswizardry
37
3.6k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
110
Transcript
Trip into the async world
Rob
Why RxJava?
Why RxJava? Retrofit
Why RxJava? Retrofit Async ops
Why RxJava? Retrofit Async ops Basic operators
Why RxJava? Retrofit Async ops Basic operators Advanced operators
Why RxJava? Retrofit Async ops Basic operators Advanced operators
Why RxJava? Retrofit Async ops Basic operators Advanced operators
implementation ‘com.squareup.retrofit2:retrofit:2.6.1’
@GET("/path/to/resource") fun networkRequest(): Single<Data> @GET("/path/to/resource") suspend fun networkRequest(): Data
Retrofit.Builder() ... .addCallAdapterFactory(CoroutineCallAdapterFactory()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build()
CoroutineCallAdapterFactory() RxJava2CallAdapterFactory.create()
@Test fun test() { runBlocking { val response = api.networkRequest()
assertThat(response)... } api.networkRequest() .test() .assertValue { } }
None
class DataViewModel()) : ViewModel() { private val subscriptions = CompositeDisposable()
val output = BehaviorSubject<LCE<Data>>.create() fun loadCurrentStatus() { disposable += store.get(BarCode.empty()) .startWith(LceLoading()) .onErrorReturn({e -> LceError(e)}) .map({data -> mapEmptyData(data)}) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(output) } override fun onCleared() { disposable.clear() } }
class DataViewModel()) : ViewModel() { private val subscriptions = CompositeDisposable()
val output = BehaviorSubject<LCE<Data>>.create() fun loadCurrentStatus() { disposable += store.get(BarCode.empty()) .startWith(LceLoading()) .onErrorReturn({e -> LceError(e)}) .map({data -> mapEmptyData(data)}) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(output) } override fun onCleared() { disposable.clear() } } Hidden knowledge
te val subscriptions = CompositeDisposable() utput = BehaviorSubject<LCE<Data>>.create() oadCurrentStatus() {
isposable += store.get(BarCode.empty()) .startWith(LceLoading()) .onErrorReturn({e -> LceError(e)}) .map({data -> mapEmptyData(data)}) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(output) ide fun onCleared() { isposable.clear() Learning curve
class DataViewModel()) : ViewModel() { val output = MutableLiveData<Data>() fun
loadCurrentStatus() { output.postValue(LceLoading()) viewModelScope.launch { try { val data = store.get(BarCode.empty()).await() if (data.isEmpty()) { output.postValue(LceError(EmptyResultSetException())) } else { output.postValue(LceSuccess(data)) } } catch (e: Exception) { output.postValue(LceError(e)) } } } }
class DataViewModel()) : ViewModel() { val output = MutableLiveData<Data>() fun
loadCurrentStatus() { output.postValue(LceLoading()) viewModelScope.launch { try { val data = store.get(BarCode.empty()).await() if (data.isEmpty()) { output.postValue(LceError(EmptyResultSetException())) } else { output.postValue(LceSuccess(data)) } } catch (e: Exception) { output.postValue(LceError(e)) } } } }
adCurrentStatus() { output.postValue(LceLoading()) viewModelScope.launch { try { val data =
store.get(BarCode.empty()).await() if (data.isEmpty()) { output.postValue(LceError(EmptyResultSetException())) } else { output.postValue(LceSuccess(data)) } } catch (e: Exception) { output.postValue(LceError(e)) } }
map flatmap filter first last
map flatmap filter first last forEach orEmpty mapNotNull
@NotNull public static <T> Observable<Response<T>> from(@NotNull final ApolloCall<T> call) {
checkNotNull(call, "call == null"); return Observable.create(new ObservableOnSubscribe<Response<T>>() { @Override public void subscribe(final ObservableEmitter<Response<T>> emitter) throws Exception { cancelOnObservableDisposed(emitter, call); call.enqueue(new ApolloCall.Callback<T>() { @Override public void onResponse(@NotNull Response<T> response) { if (!emitter.isDisposed()) { emitter.onNext(response); } } @Override public void onFailure(@NotNull ApolloException e) { Exceptions.throwIfFatal(e); if (!emitter.isDisposed()) { emitter.onError(e); } } @Override public void onStatusEvent(@NotNull ApolloCall.StatusEvent event) { if (event == ApolloCall.StatusEvent.COMPLETED && !emitter.isDisposed()) { emitter.onComplete(); } } }); } }); }
@NotNull public static <T> Observable<Response<T>> from(@NotNull final ApolloCall<T> call) {
checkNotNull(call, "call == null"); return Observable.create(new ObservableOnSubscribe<Response<T>>() { @Override public void subscribe(final ObservableEmitter<Response<T>> emitter) throws Exception { cancelOnObservableDisposed(emitter, call); call.enqueue(new ApolloCall.Callback<T>() { @Override public void onResponse(@NotNull Response<T> response) { if (!emitter.isDisposed()) { emitter.onNext(response); } } @Override public void onFailure(@NotNull ApolloException e) { Exceptions.throwIfFatal(e); if (!emitter.isDisposed()) { emitter.onError(e); } } @Override public void onStatusEvent(@NotNull ApolloCall.StatusEvent event) { if (event == ApolloCall.StatusEvent.COMPLETED && !emitter.isDisposed()) { emitter.onComplete(); } } }); } }); } suspend fun <T> ApolloCall<T>.await(): Response<T> = suspendCancellableCoroutine { cont -> enqueue(object : ApolloCall.Callback<T>() { override fun onFailure(e: ApolloException) { cont.resumeWithException(e) } override fun onResponse(response: Response<T>) { cont.resume(response) } }) cont.invokeOnCancellation { cancel() } }
suspend fun <T> ApolloCall<T>.await(): Response<T> = suspendCancellableCoroutine { cont ->
enqueue(object : ApolloCall.Callback<T>() { override fun onFailure(e: ApolloException) { cont.resumeWithException(e) } override fun onResponse(response: Response<T>) { cont.resume(response) } }) cont.invokeOnCancellation { cancel() } }
val job = Job() val scope = CoroutineScope(Dispatchers.IO + job)
fun doThings() { scope.launch { ... } } fun inTheEnd() { job.cancel() }
val job = Job() val scope = CoroutineScope(Dispatchers.IO + job)
fun doThings() { scope.launch { ... } } fun inTheEnd() { job.cancelChildren() scope.coroutineContext.cancelChildren() }
job.cancelChildren() scope.coroutineContext.cancelChildren() public fun Job.cancelChildren(cause: CancellationException? = null) { children.forEach
{ it.cancel(cause) } } public fun CoroutineContext.cancelChildren(cause: CancellationException? = null) { this[Job]?.children?.forEach { it.cancel(cause) } }
None
kotlinx-coroutines-rx2
class RxThing { fun doStuff() : Single<MyData> }
suspend fun doThings() { val my data = rxThing.doStuff().await() }
class CoroutineThing { suspend fun doStuff() : MyData }
fun doStuff() : Single<MyData> = rxSingle { coroutineThing.doStuff() }
fun doStuff() : Single<MyData> = rxSingle(RxCoroutineExceptionHandler) { coroutineThing.doStuff() }
None
open.nytimes.com @nytdev github.com/NYTimes developers.nytimes.com
QA &