This deck is the base of the presentation about migrating from RxJava to Coroutines I gave at Conference for Kotliners, in Budapest
Trip into theasync world
View Slide
Rob
Why RxJava?
Why RxJava?Retrofit
Why RxJava?RetrofitAsync ops
Why RxJava?RetrofitAsync opsBasic operators
Why RxJava?RetrofitAsync opsBasic operatorsAdvanced operators
implementation'com.squareup.retrofit2:retrofit:2.6.0’
@GET("/path/to/resource")fun networkRequest(): Single@GET("/path/to/resource")suspend fun networkRequest(): Data
Retrofit.Builder()....addCallAdapterFactory(CoroutineCallAdapterFactory()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build()
CoroutineCallAdapterFactory()RxJava2CallAdapterFactory.create()
@Testfun test() {runBlocking {val response =api.networkRequest()assertThat(response)...}api.networkRequest().test().assertValue { }}
class DataViewModel()) : ViewModel() {private val subscriptions = CompositeDisposable()val output = BehaviorSubject>.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>.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>.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()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))}}
mapflatmapfilterfirstlast
mapflatmapfilterfirstlastforEachorEmptyTmapNotNull
@NotNull public static Observable> from(@NotNull final ApolloCall call) {checkNotNull(call, "call == null");return Observable.create(new ObservableOnSubscribe>() {@Override public void subscribe(final ObservableEmitter> emitter) throws Exception {cancelOnObservableDisposed(emitter, call);call.enqueue(new ApolloCall.Callback() {@Override public void onResponse(@NotNull Response 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 Observable> from(@NotNull final ApolloCall call) {checkNotNull(call, "call == null");return Observable.create(new ObservableOnSubscribe>() {@Override public void subscribe(final ObservableEmitter> emitter) throws Exception {cancelOnObservableDisposed(emitter, call);call.enqueue(new ApolloCall.Callback() {@Override public void onResponse(@NotNull Response 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 ApolloCall.await(): Response =suspendCancellableCoroutine { cont ->enqueue(object : ApolloCall.Callback() {override fun onFailure(e: ApolloException) {cont.resumeWithException(e)}override fun onResponse(response: Response) {cont.resume(response)}})cont.invokeOnCancellation { cancel() }}
suspend fun ApolloCall.await(): Response =suspendCancellableCoroutine { cont ->enqueue(object : ApolloCall.Callback() {override fun onFailure(e: ApolloException) {cont.resumeWithException(e)}override fun onResponse(response: Response) {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) }}
open.nytimes.com@nytdevgithub.com/NYTimesdevelopers.nytimes.com
QA&