Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Trip into the async world

Trip into the async world

This deck is the base of the presentation about migrating from RxJava to Coroutines I gave at Conference for Kotliners, in Budapest

Roberto Orgiu

June 07, 2019
Tweet

More Decks by Roberto Orgiu

Other Decks in Programming

Transcript

  1. Trip into the
    async world

    View Slide

  2. Rob

    View Slide

  3. Why RxJava?

    View Slide

  4. Why RxJava?
    Retrofit

    View Slide

  5. Why RxJava?
    Retrofit
    Async ops

    View Slide

  6. Why RxJava?
    Retrofit
    Async ops
    Basic operators

    View Slide

  7. Why RxJava?
    Retrofit
    Async ops
    Basic operators
    Advanced operators

    View Slide

  8. Why RxJava?
    Retrofit
    Async ops
    Basic operators
    Advanced operators

    View Slide

  9. Why RxJava?
    Retrofit
    Async ops
    Basic operators
    Advanced operators

    View Slide

  10. implementation
    'com.squareup.retrofit2:retrofit:2.6.0’

    View Slide

  11. @GET("/path/to/resource")
    fun networkRequest(): Single
    @GET("/path/to/resource")
    suspend fun networkRequest(): Data

    View Slide

  12. Retrofit.Builder()
    ...
    .addCallAdapterFactory(CoroutineCallAdapterFactory())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build()

    View Slide

  13. CoroutineCallAdapterFactory()
    RxJava2CallAdapterFactory.create()

    View Slide

  14. @Test
    fun test() {
    runBlocking {
    val response =
    api.networkRequest()
    assertThat(response)...
    }
    api.networkRequest()
    .test()
    .assertValue { }
    }

    View Slide

  15. View Slide

  16. 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()
    }
    }

    View Slide

  17. 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

    View Slide

  18. 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

    View Slide

  19. 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))
    }
    }
    }
    }

    View Slide

  20. 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))
    }
    }
    }
    }

    View Slide

  21. 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))
    }
    }

    View Slide

  22. map
    flatmap
    filter
    first
    last

    View Slide

  23. map
    flatmap
    filter
    first
    last
    forEach
    orEmptyT
    mapNotNull

    View Slide

  24. @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();
    }
    }
    });
    }
    });
    }

    View Slide

  25. @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() }
    }

    View Slide

  26. 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() }
    }

    View Slide

  27. val job = Job()
    val scope = CoroutineScope(Dispatchers.IO + job)
    fun doThings() {
    scope.launch {
    ...
    }
    }
    fun inTheEnd() {
    job.cancel()
    }

    View Slide

  28. val job = Job()
    val scope = CoroutineScope(Dispatchers.IO + job)
    fun doThings() {
    scope.launch {
    ...
    }
    }
    fun inTheEnd() {
    job.cancelChildren()
    scope.coroutineContext.cancelChildren()
    }

    View Slide

  29. 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) }
    }

    View Slide

  30. View Slide

  31. open.nytimes.com
    @nytdev
    github.com/NYTimes
    developers.nytimes.com

    View Slide

  32. QA
    &

    View Slide