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

Android Lx - 25 Jan 2017 - RxJava: More than the basic

Android Lx - 25 Jan 2017 - RxJava: More than the basic

Sérgio Marques Moura

January 25, 2017
Tweet

More Decks by Sérgio Marques Moura

Other Decks in Technology

Transcript

  1. Wrap your app’s callback APIs with RxJava Why? - Android

    apps’ event-based fashion - Many 3rd party APIs: - Work assynchronously - Can be modeled by a stream of events - Preventing ending up with “callback hells”
  2. 1. TwitterApi twitterApi = TwitterApiFactory().getInstance(); 2. 3. button.setOnClickListener(view -> {

    4. twitterApi.getTweets(new TweetListener() { 5. 6. @Override 7. public void onTweetReceived(Tweet tweet) { 8. latestTweet.setText(tweet.getContent()); 9. } 10. 11. @Override 12. public void onError(Exception exception) { 13. latestTweet.setText("Error getting tweets! Cause: " + exception.getMessage()); 14. } 15. }); 16. }); • Too much code • Poorly readable • Hinders multithreading • No separation between technical and business domains
  3. 1. public class RxTwitterInteractor { 2. 3. Observable<Tweet> observe() {

    4. return Observable.create(subscriber -> { 5. TwitterApi twitterApi = new TwitterApiFactory().getInstance(); 6. 7. twitterApi.getTweets(new TweetListener() { 8. @Override 9. public void onTweetReceived(Tweet tweet) { 10. subscriber.onNext(tweet); 11. } 12. 13. @Override 14. public void onError(Throwable throwable) { 15. subscriber.onError(throwable); 16. } 17. }); 18. 19. subscriber.add(Subscriptions.create(twitterApi::shutdown)); 20. }); 21. } 22. } Automatic resource cleanup on unsubscription
  4. 1. CompositeSubscription subscriptions = new CompositeSubscription(); 2. 3. subscriptions.add(rxTwitterInteractor.observe() 4.

    .subscribeOn(Schedulers.io()) 5. .observeOn(AndroidSchedulers.mainThread()) 6. .subscribe(new Subscriber<Tweet>() { 7. @Override 8. public void onCompleted() { 9. // empty 10. } 11. 12. @Override 13. public void onError(Throwable e) { 14. view.showError(e); 15. } 16. 17. @Override 18. public void onNext(Tweet tweet) { 19. view.displayTweet(tweet); 20. } 21. })); Better, but.. • Every subscriber still opens a new connection • The observable instance should be reusable
  5. 1. class RxTwitterSubject { 2. 3. private final PublishSubject<Tweet> subject

    = PublishSubject.create(); 4. 5. public RxTwitterSubject() { 6. TwitterApi twitterApi = new TwitterApiFactory().getInstance(); 7. 8. twitterApi.getTweets(new TweetListener() { 9. @Override 10. public void onTweetReceived(Tweet tweet) { 11. subject.onNext(tweet); 12. } 13. 14. @Override 15. public void onError(Throwable throwable) { 16. subject.onError(throwable); 17. } 18. }); 19. } 20. 21. public Observable<Tweet> observe() { 22. return subject; 23. } 24. } Treating subject as an Observable Treating subject as an Observer • Only one reusable connection • Every Subscriber will receive subsequent events after subscribing
  6. rx.Subject flavors • AsyncSubject ◦ Remembers the last emitted value,

    only pushes to every subscriber when onComplete() is called • BehaviorSubject ◦ Emits the most recent event on subscription, and every subsequent event after that • ReplaySubject ◦ Caches all events pushed through it, emits them all before real-time events to every new subscriber ◦ ReplaySubject.createWithSize(int n) ◦ ReplaySubject.createWithTime(long time) ◦ ReplaySubject.createWithTimeAndSize(long time, int n)
  7. 1. class RxTwitterSubject { 2. 3. ... 4. 5. public

    Observable<Tweet> observe() { 6. return subject; 7. } 8. 9. public Completable init() { 10. twitterApi.init("MyApiKey"); 11. 12. twitterApi.getTweets(new TweetListener() { 13. @Override 14. public void onTweetReceived(Tweet tweet) { 15. subject.onNext(tweet); 16. } 17. 18. @Override 19. public void onError(Throwable throwable) { 20. subject.onError(throwable); 21. } 22. }); 23. 24. return Completable.complete(); 25. } 26. } Notifying the initialization completion 1. subscriptions.add(rxTwitterSubject.init() 2. .andThen(rxTwitterSubject.observe()) 3. .subscribeOn(Schedulers.io())
  8. 1. subscriptions.add(rxTwitterSubject.init() 2. .andThen(rxTwitterSubject.getCount()) 3. .flatMapObservable(count -> rxTwitterSubject.observe()) 4. .subscribeOn(Schedulers.io())

    1. class RxTwitterSubject { 2. 3. private final PublishSubject<Tweet> subject = PublishSubject.create(); 4. 5. public RxTwitterSubject() { 6. TwitterApi twitterApi = new TwitterApiFactory().getInstance(); 7. } 8. 9. public Observable<Tweet> observe() { 10. return subject; 11. } 12. 13. ... 14. 15. public Single getCount() { 16. return Single.just(subject.count()); 17. } 18. }
  9. 1. subscriptions.add(rxTwitterSubject.init() 2. .andThen(rxTwitterSubject.getCount()) 3. .flatMapObservable(count -> rxTwitterSubject.observe()) 4. .doOnSubscribe(()

    -> log("Subscribed to the tweets...")) 5. .subscribeOn(Schedulers.io()) 6. .observeOn(AndroidSchedulers.mainThread())
  10. 1. subscriptions.add(rxTwitterSubject.init() 2. .andThen(rxTwitterSubject.getCount()) 3. .flatMapObservable(count -> rxTwitterSubject.observe()) 4. .doOnSubscribe(()

    -> log("Subscribed to the tweets...")) 5. .doOnNext(tweet -> view.displayTweet(tweet)) 6. .subscribeOn(Schedulers.io()) 7. .observeOn(AndroidSchedulers.mainThread()) Where’s the problem?
  11. 1. subscriptions.add(rxTwitterSubject.init() 2. .andThen(rxTwitterSubject.getCount()) 3. .flatMapObservable(count -> rxTwitterSubject.observe()) 4. .doOnSubscribe(()

    -> log("Subscribed to the tweets...")) .observeOn(AndroidSchedulers.mainThread()) 5. .doOnNext(tweet -> view.displayTweet(tweet)) 6. .subscribeOn(Schedulers.io())
  12. 1. subscriptions.add(rxTwitterSubject.init() 2. .andThen(rxTwitterSubject.getCount()) 3. .flatMapObservable(count -> rxTwitterSubject.observe()) 4. .doOnSubscribe(()

    -> log("Subscribed to the tweets...")) 5. .observeOn(AndroidSchedulers.mainThread()) 6. .doOnNext(tweet -> view.displayTweet(tweet)) 7. .doOnCompleted(() -> log("Finished fetching tweets!")) 8. .subscribeOn(Schedulers.io())
  13. 1. subscriptions.add(rxTwitterSubject.init() 2. .andThen(rxTwitterSubject.getCount()) 3. .flatMapObservable(count -> rxTwitterSubject.observe()) 4. .doOnSubscribe(()

    -> log("Subscribed to the tweets...")) 5. .observeOn(AndroidSchedulers.mainThread()) 6. .doOnNext(tweet -> view.displayTweet(tweet)) 7. .doOnCompleted(() -> log("Finished fetching tweets!")) 8. .doOnError(throwable -> log("Error: "+throwable.getMessage())) 9. .subscribeOn(Schedulers.io())
  14. 1. subscriptions.add(rxTwitterSubject.init() 2. .andThen(rxTwitterSubject.getCount()) 3. .flatMapObservable(count -> rxTwitterSubject.observe()) 4. .doOnSubscribe(()

    -> log("Subscribed to the tweets...")) 5. .observeOn(AndroidSchedulers.mainThread()) 6. .doOnNext(tweet -> view.displayTweet(tweet)) 7. .doOnCompleted(() -> log("Finished fetching tweets!")) 8. .doOnError(throwable -> log("Error: "+throwable.getMessage())) 9. .onErrorReturn(new Tweet("This is the end!")) 10. .subscribeOn(Schedulers.io())