Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Trip into the async world @ NYC Kotlin Meetup
Search
Roberto Orgiu
October 16, 2019
Programming
140
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
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
140
Behind the curtains
tiwiz
0
99
The Importance of Being Tested
tiwiz
0
470
An Android Dev start to Kotlin MPP
tiwiz
0
220
Fantastic API and where to find them
tiwiz
0
120
Flipping the Koin @ GDG Dev Party
tiwiz
1
84
Flipping the Koin
tiwiz
2
190
Trip into the async world
tiwiz
1
170
GraphQL IRL (Android Makers)
tiwiz
0
170
Other Decks in Programming
See All in Programming
AIで開発が速くなった先で、開発チームは何を目指すか
shihochan
1
1.9k
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
500
graphql-ruby を Spinel で速くしようとした話
mtsmfm
0
130
複雑なUIコンポーネントとの ⻑い付き合い⽅:波及するバグからテスト戦略を経て、安全な再設計へ
mixplace
0
490
AI時代のFlutter品質設計 — アプリ品質を守るQuality Layers
omatty198
0
320
No More NoSuchMethodError
exoego
1
120
Vapor Mode でアクセシビリティは 壊れないか検証した話
fuqda
1
280
SFCで実現する病院・医療システムの動的組み立て式UI
koukimiura
1
140
AmebaブログはKMPから卒業します
kmars0605
0
310
dotNET_vulnclicker_intro.pdf
deka_morita
0
160
全ての永続トークンを、生まれる前に消し去りたい!
sylph01
2
1.6k
sbt 2.0: takeoff
eed3si9n
0
180
Featured
See All Featured
Automating Front-end Workflow
addyosmani
1370
210k
Site-Speed That Sticks
csswizardry
13
1.6k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
59k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.4k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.9k
Embracing the Ebb and Flow
colly
88
5.2k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
540
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.7k
Designing Experiences People Love
moore
143
24k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
500
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.5k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
550
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 &