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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
GraphQL の onError と Nullability のこれから
quramy
0
200
Python Lambdaにおけるテストしやすい設計とAI支援の活用 / Designing Testable Python Lambda Functions with AI
kitano_yuichi
1
250
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
220
TS 7.0 で baseUrl が使えなくなった今、パスエイリアスをどうするか
bicstone
1
270
graphql-ruby を Spinel で速くしようとした話
mtsmfm
0
130
Vue.jsで作る空間解析アプリとCapacitorプラグインのData Bridge
hal_spidernight
1
130
エージェントを使い続けるためのメタワーク / Meta-work for keeping using the agent
rkaga
6
2k
AI時代のシニアエンジニアとは
yosuke_furukawa
PRO
12
11k
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Kaigi on Rails 2026, Tokyo, Japan
marcoroth
2
370
Performance Optimization With LLMs
xleitix
0
230
Coding with AI: How to trust the storyteller (AWS Community Day Adria, Ljubljana 2026)
slobodan
0
130
Groovy as a human and AI friendly programming language
paulk
0
140
Featured
See All Featured
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.4k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
460
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
31k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.2k
The browser strikes back
jonoalderson
0
1.9k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.7k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Believing is Seeing
oripsolob
1
260
Paper Plane
katiecoart
PRO
5
54k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7.1k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.4k
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 &