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

ReactiveX in Android

ReactiveX in Android

An introduction to RxJava and RxAndroid (v1) and Rx patterns

Richard Cirerol

March 19, 2016
Tweet

More Decks by Richard Cirerol

Other Decks in Programming

Transcript

  1. The Observer pattern done right 4 Observer pattern 4 Iterator

    pattern 4 Functional programming 4 Asynchronous RxAndroid | Richard Cirerol | @codeprogression
  2. RxJava is a port of Rx.NET started by Netflix (circa

    2013) RxAndroid | Richard Cirerol | @codeprogression
  3. Languages - Java: RxJava - JavaScript: RxJS - C#: Rx.NET

    - C#(Unity): UniRx - Scala: RxScala - Clojure: RxClojure - C++: RxCpp - Ruby: Rx.rb - Python: RxPY - Groovy: RxGroovy - JRuby: RxJRuby - Kotlin: RxKotlin - Swift: RxSwift ReactiveX for platforms and frameworks - RxNetty - RxAndroid - RxCocoa RxAndroid | Richard Cirerol | @codeprogression
  4. Observable 4 Emits a stream of items to observers 4

    Notifies observers of termination events 4 Error 4 Completed RxAndroid | Richard Cirerol | @codeprogression
  5. Integer[] items = new Integer[]{ 2, 4, 6, 8, 10

    } Observable.from(items); RxAndroid | Richard Cirerol | @codeprogression
  6. Observable.create(new OnSubscribe<Integer>() @Override public void call(Observer Observer){} try{ for (int

    i = 0; i < 5; i++){ observer.onNext(i); } observer.onCompleted() } catch(Exception e){ observer.onError(e); } } }); RxAndroid | Richard Cirerol | @codeprogression
  7. Observer 4 Subscribes to an Observable 4 Reacts to emitted

    items 4 Reacts to termination events RxAndroid | Richard Cirerol | @codeprogression
  8. public interface Observer<T> { void onNext(T item); void onError(Throwable t);

    void onCompleted(); } RxAndroid | Richard Cirerol | @codeprogression
  9. From a DB? A web service? A singleton? RxAndroid |

    Richard Cirerol | @codeprogression
  10. Observer to Observable: Just tell me when you've got something

    new And tell me when you're done RxAndroid | Richard Cirerol | @codeprogression
  11. Listener 4 Registration managed by the parent of the target

    4 Callback interfaces are custom per implementation RxAndroid | Richard Cirerol | @codeprogression
  12. // Before calling... service.getFoo(); // First call one of... service.setListener(this);

    service.addListener(this); // And implement... public interface Listener { void onFooChanged(Foo foo); } // And remember to clean up... service.setListener(null); service.removeListener(this); RxAndroid | Richard Cirerol | @codeprogression
  13. Observables 4 Registration managed internally by the Observable 4 Subscription

    interface is consistent RxAndroid | Richard Cirerol | @codeprogression
  14. // A Subscriber is a subclass of Observer Subscription subscription

    = service.getFoo() .subscribe(new Subscriber<Foo>(){ @Override public void onNext(Foo item){ doSomething(item); } @Override public void onError(Throwable e){ Log.e(e); } @Override public void onCompleted(){ hideProgress(); } }); RxAndroid | Richard Cirerol | @codeprogression
  15. Subscription subscription = service.getFoo() .subscribe(new Action1<Foo>(){ @Override public void call(Foo

    foo){ doSomething(foo)); } }); RxAndroid | Richard Cirerol | @codeprogression
  16. Subscription subscription = service.getFoo() .subscribe(new Action1<Foo>(){ @Override public void call(Foo

    foo){ doSomething(foo)); } }, new Action<Throwable>(){ @Override public void call(Throwable t){ Log.e(t); } }); RxAndroid | Richard Cirerol | @codeprogression
  17. Operators 4 Are a specialized observer 4 Can transform observables

    4 Can be chained 4 A function that takes a Subscriber and returns a Subscriber RxAndroid | Richard Cirerol | @codeprogression
  18. Observable.from({0, 1, 2, 3, 4}) .skip(1) .map(new Func1<Integer, Integer>(){ @Override

    public Integer call(Integer in){ return in^2; } }) .subscribe(); RxAndroid | Richard Cirerol | @codeprogression
  19. Observable.from({0, 1, 2, 3, 4}) .doOnNext(new Action1<Integer>(){ @Override public void

    call(Integer in){ return Log.i("Received: " + in); } }) .subscribe(); RxAndroid | Richard Cirerol | @codeprogression
  20. Observable<Player> player; Observable<List<Team>> teams; Observable.combineLatest(player, teams, new Func2<Player, List<Team>, ViewModel>(){

    @Override public ViewModel(Player player, List<Team> teams){ Team team = teams.get(player.getTeamId()); return new ViewModel(player.getName(), team.getName()); } }) .subscribe(...); RxAndroid | Richard Cirerol | @codeprogression
  21. Observables are asynchronous by default A subscription will not block

    the thread when waiting for a value. RxAndroid | Richard Cirerol | @codeprogression
  22. toBlocking() makes an Observable synchronous A subscription WILL block the

    thread when waiting for a value. RxAndroid | Richard Cirerol | @codeprogression
  23. Schedulers RxJava allows you to marshall operations to another thread.

    RxAndroid | Richard Cirerol | @codeprogression
  24. // in publisher class public Observable<Bar> getBar(){ return Observable.create(s ->

    getFooFromWeb()) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(foo -> calculateBar(foo)) } // in subscriber class (presenter?) getBar() .observeOn(AndroidSchedulers.mainThread()); .subscribe(item -> updateView(item)); RxAndroid | Richard Cirerol | @codeprogression
  25. private Bar cachedBar; public Observable<Bar> getBar(){ return Observable.create(s -> getFooFromWeb())

    .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(foo -> calculateBar(foo)) .doOnNext(bar -> cachedBar = bar) } RxAndroid | Richard Cirerol | @codeprogression
  26. private Bar cachedBar; public Observable<Bar> getBar(){ if (cachedBar != null){

    return Observable.just(cachedBar); } else { return Observable.create(s -> getFooFromWeb()) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(foo -> calculateBar(foo)) .doOnNext(bar -> cachedBar = bar) } } RxAndroid | Richard Cirerol | @codeprogression
  27. public void onResume(){ subscription = publisher.getFoo().subscribe(...); } public void onPause(){

    subscription.unsubscribe(); } RxAndroid | Richard Cirerol | @codeprogression
  28. public void onResume(){ subscription1 = publisher.getFoo().subscribe(...); subscription2 = publisher.getBar().subscribe(...); subscription3

    = publisher.getBaz().subscribe(...); } public void onPause(){ subscription1.unsubscribe(); subscription2.unsubscribe(); subscription3.unsubscribe(); } RxAndroid | Richard Cirerol | @codeprogression
  29. CompositeSubscription subscriptions; public void onResume(){ subscriptions = new CompositeSubscription(); subscriptions.add(publisher.getFoo().subscribe(...));

    subscriptions.add(publisher.getBar().subscribe(...)); subscriptions.add(publisher.getBaz().subscribe(...)); } public void onPause(){ subscriptions.unsubscribe(); } RxAndroid | Richard Cirerol | @codeprogression
  30. Warning Once unsubscribed, a CompositeSubscription will not manage any new

    subscriptions. RxAndroid | Richard Cirerol | @codeprogression
  31. Case Study Problem: Retrieve a video url for a program

    RxAndroid | Richard Cirerol | @codeprogression
  32. Case Study Problem: Retrieve a video url for a program

    RxAndroid | Richard Cirerol | @codeprogression
  33. String id = getIntent().getStringExtra("PROGRAM_ID", id); subscription = publisher.getVideoUrl(id) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new

    Subscriber<String>(){ @Override public void onCompleted() {} @Override public void onError(final Throwable e) { } @Override public void onNext(final String url) { player.load(url); } }); RxAndroid | Richard Cirerol | @codeprogression
  34. Retrofit 4 http://square.github.io/retrofit 4 Type-safe HTTP client 4 RxJava capable

    (with adapter) RxAndroid | Richard Cirerol | @codeprogression
  35. // VideoService.java public Observable<String> getVideoUrl(String id){ api.getVideo() // return a

    url from the Video object } RxAndroid | Richard Cirerol | @codeprogression
  36. // VideoService.java public Observable<String> getVideoUrl(String id){ api.getVideo() .map(new Func1<Video, String>{

    @Override public String call(Video video){ return video.getUrl(); } }); } RxAndroid | Richard Cirerol | @codeprogression
  37. // VideoService.java public Observable<String> getVideoUrl(String id){ api.getVideo() .subscribeOn(Schedules.io) .map(new Func1<Video,

    String>(){ @Override public String call(Video video){ return video.getUrl(); } }); } RxAndroid | Richard Cirerol | @codeprogression
  38. public interface VideoApi { @GET("/video/{id}") Observable<Video> getVideo( @Header("Authorization") auth, @Path("id")

    String id); @POST("/token") Observable<String> getToken(@Body TokenRequest request); } RxAndroid | Richard Cirerol | @codeprogression
  39. // VideoService.java public Observable<String> getVideoUrl(String id){ api.getToken(tokenRequest) .subscribeOn(Schedules.io) ... api.getVideo()

    .map(new Func1<Video, String>{ @Override public String call(Video video){ return video.getUrl(); } }); } RxAndroid | Richard Cirerol | @codeprogression
  40. flatMap() Transform each item into one or more Observables, then

    flatten RxAndroid | Richard Cirerol | @codeprogression
  41. // VideoService.java private TokenRequest request; public Observable<String> getVideoUrl(final String id){

    api.getToken(tokenRequestBody) .subscribeOn(Schedules.io) .flatMap(new Func1<String, Observable<Video>(){ @Override public Observable<Video> call(String token){ return api.getVideo(token, id); } }) .map(new Func1<Video, String>(){ @Override public String call(Video video){ return video.getUrl(); } }); } RxAndroid | Richard Cirerol | @codeprogression
  42. RxAndroid = Observables + Operators + Schedulers + Additional Schedulers

    RxAndroid | Richard Cirerol | @codeprogression
  43. Observables 4 stream data to observers 4 also notify observers

    of termination events RxAndroid | Richard Cirerol | @codeprogression
  44. Operators 4 transform data 4 provide side effects 4 affect

    either 4 items 4 observable RxAndroid | Richard Cirerol | @codeprogression
  45. Subscribers 4 act on the emitted items and notifications 4

    are protected from synchronicity or concurrency concerns RxAndroid | Richard Cirerol | @codeprogression