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

RxJava on Android

Marco Fuhrich
February 07, 2017

RxJava on Android

My talk for the Android Developer Group in Nuremberg

Demo code available here: https://github.com/mrcktz/RxJavaExamples

Marco Fuhrich

February 07, 2017
Tweet

Other Decks in Technology

Transcript

  1. Asynchronous Programming on Android Why? • Application Performance • User

    Experience (non-blocking) How? • Handler, Messenger, Runnable (HaMeR Framework) • AsyncTask • Loader • Service • ...
  2. Reactive Programming and Android Apps live in a very asynchronous

    environment • Configuration changes • Unreliable networking • Broadcasts • User Input A constant flow of changes and events has to be dispatched and handled while staying responsive and resilient.
  3. RxJava, pants down! • Observables: Classes representing different types of

    sources of data • Observers: Classes that enable you to listen to those sources • Operators: Methods for modifying and composing streams and data CREATE STREAM LISTEN TO STREAM MODIFY/ COMBINE STREAM
  4. RxJava, pants down! • Observables: Classes representing different types of

    sources of data • Observers: Classes that enable you to listen to those sources • Operators: Methods for modifying and composing streams and data Flowable<T> and Observable<T> • the source of our data • synchronous or asynchronous • 0, 1 or n items can be emitted • terminates never or by calling onComplete() or onError()
  5. RxJava, pants down! • Observables: Classes representing different types of

    sources of data • Observers: Classes that enable you to listen to those sources • Operators: Methods for modifying and composing streams and data Flowable<T>: Handles backpressure, subscribe with: public void subscribe(Subscriber<T>); Observable<T>: No backpressure, subscribe with: public void subscribe(Observer<T>); Backpressure is the reactive way to deal with a common problem: An Observable emits items too fast for the Observer to consume it.
  6. RxJava, pants down! • Observables: Classes representing different types of

    sources of data • Observers: Classes that enable you to listen to those sources • Operators: Methods for modifying and composing streams and data Subscribe to a Flowable by implementing: public interface Subscriber<T> { public void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); } Subscribe to an Observable by implementing: public interface Observer<T> { public void onSubscribe(Disposable d); public void onNext(T t); public void onError(Throwable t); public void onComplete(); }
  7. Flowable<T> and Observable<T> offer operators that allow you to •

    manipulate data • manipulate threads (schedulers) • manipulate emission of data RxJava, pants down! • Observables: Classes representing different types of sources of data • Observers: Classes that enable you to listen to those sources • Operators: Methods for modifying and composing streams and data
  8. Whatever, now show me some code! Observable.just("Hello World").subscribe(System. out::println); This

    creates on Observable, subscribes to it and passes the String emitted through onNext(String next) to System.out.println.
  9. Create Data: Observables Observable.just("Hello World").subscribe(System. out::println); Create an Observable: Observable.just("Hello");

    Observable.just("Hello", "World"); Observable.fromArray(new int[]{1, 2, 3, 4}); Observable.fromCallable(() -> api.connect("email", "pass")); Observable.fromIterable(Arrays.asList(new int[]{1, 2, 3, 4})); Observable.fromFuture(() -> api.connect("email", "pass")); Or get all the freedom by using Observable.create(): Observable.create(e -> { e.onNext("Hello"); e.onNext("World"); e.onComplete() ; });
  10. Create Data: Observables Observable.just("Hello World").subscribe(System. out::println); There are special types

    of sources: Maybe, Single and Completable Maybe.fromRunnable(() -> System. out.println("Hello World")); Maybe.fromAction(() -> System. out.println("Hello World")); Completable.fromRunnable(() -> System. out.println("Completed!")); Completable.fromAction(() -> System. out.println("Completed!")); Completable: onComplete() or onError() will be called. Maybe: onSuccess(T t) or onComplete() or onError() Single: onSuccess(T t) or onError() will be called.
  11. Listen To Data: Subscribe Observable.just("Hello World").subscribe(System. out::println); Observable.just("Hello World").subscribe(new DisposableObserver<String>()

    { @Override public void onNext(String value) { System.out.println(value); } @Override public void onError(Throwable e) { ... } @Override public void onComplete() { ... } });
  12. Listen To Data: Subscribe Observable<User> userObservable = Observable.fromCallable(() -> api.getUserByMail(

    "[email protected]")); userObservable.subscribe( user -> helloTextView.setText("Hi" + user.nickname + "!"); );
  13. Listen To Data: Subscribe Observable<User> userObservable = Observable.fromCallable(() -> api.getUserByMail(

    "[email protected]")); userObservable.subscribe( user -> helloTextView.setText( "Hi" + user.nickname + "!"); ); Problems: • Potentially long running network operation! • We may not need the result anymore • Memory leaks
  14. Listen To Data: Subscribe CompositeDisposable disposables = new CompositeDisposable() ;

    Observable<User> userObservable = Observable.fromCallable(() -> api.getUserByMail( "[email protected]")); DisposableObserver<User> disposable = userObservable.subscribeWith ( user -> helloTextView.setText( "Hi" + user.nickname + "!"); ); disposables.add(disposable) ;
  15. Listen To Data: Subscribe You can now dispose the Observer

    whenever it’s appropriate: @Override protected void onDestroy() { disposables.dispose(); }
  16. Listen To Data: Subscribe Observable<User> userObservable = Observable.fromCallable(() -> api.getUserByMail(

    "[email protected]")); userObservable.subscribe( user -> helloTextView.setText( "Hi" + user.nickname + "!"); ); Problems: • Potentially long running network operation! • We may not need the result anymore • Memory leaks • NetworkOnMainThreadException
  17. Schedulers userObservable .observeOn(Schedulers.io()) .subscribeOn(AndroidSchedulers.mainThread()) .subscribeWith( user -> helloTextView.setText("Hi" + user.nickname

    + "!"; ); observeOn(Schedulers.io()): Networking will run in a background thread taken from the Thread pool of Schedulers.io() subscribeOn(AndroidSchedulers.mainThread()): All work that the Observer does will be done on the MainThread
  18. Modify / Combine Data: Operators List<String> searchTerms = Arrays. asList("Wh",

    "Obama", "Trump", "w", "Tr"); Observable.fromIterable(searchTerms) // Filter the search terms .filter(s -> s.length() > 2) // Create new SearchRequests from those search terms .flatMap(s -> Observable. just(new SearchRequest(s , time))) // Reduce the results to a single StringBuilder object .reduce(new StringBuilder() , (stringBuilder , searchRequest) -> stringBuilder.append(searchRequest.result())) // Print out the result .subscribe(System. out::print, e -> e.printStackTrace()) ;
  19. Modify / Combine Data: Operators • There are a lot

    of useful operators available • It’s not always obvious what they are doing • RxMarbles were invented to visualize the operations
  20. Example: Button clicks per second RxView.clicks(clickButton ) .buffer( 1, TimeUnit.SECONDS)

    .filter((clicks) -> clicks.size() > 0)) .subscribe((count) -> System. out.println(count + " clicks/s" )); Do not forget to dispose as there’s a strong reference to clickButton.
  21. Example: Form Validation First Step: Create data Flowable<Boolean> emailObservable =

    RxTextView.textChanges(mEmailView) .flatMap((chars) -> Flowable.just(mEmailView.getText() != null && isEmailValid(mEmailView.getText().toString()))).skip(1); Flowable<Boolean> passwordObservable = RxTextView.textChanges(mPasswordView) .flatMap((chars) -> Flowable.just(mPasswordView.getText() != null && isPasswordValid(mPasswordView.getText().toString()))).skip(1);
  22. Example: Form Validation Second Step: Modify / Combine data Flowable.combineLatest(emailObservable

    , passwordObservable , (emailValid, passwordValid) -> { if (!emailValid) { mEmailView.setError("Email invalid" ); } if (!passwordValid) { mPasswordView.setError("Password invalid" ); } return emailValid && passwordValid ; }).subscribeWith( mFormValidationDisposable );
  23. Example: Form Validation Third Step: Listen to data mFormValidationDisposable =

    new DisposableSubscriber<Boolean>() { @Override public void onNext(Boolean formValid) { mEmailSignInButton .setEnabled(formValid) ; } @Override public void onError(Throwable t) { /* Error */ } @Override public void onComplete() { /* Completed */ } }; Flowable.combineLatest(...).subscribeWith( mFormValidationDisposable );
  24. Other Real-World examples and their operators (taken from Kaushik Gopals

    open source effort to collect good samples for RxJava usecases) • Instant/Auto searching text listeners (using Subjects & debounce) • Two-way data binding (using PublishSubject) • Polling (using interval and repeatWhen) • Exponential backoff (using delay and retryWhen) • Eventbus (using RxRelay and debounceBuffer) • Orchestrating Observable: make parallel network calls, then combine the result into a single data point (using flatmap & zip) …. https://github.com/kaushikgopal/RxJava-Android-Samples
  25. Sources and Resources • Adopting RxJava on Airbnb Android http://de.droidcon.com/sites/global.droidcon.cod.newthinking.net/files/media/documents/Adopting%20RxJav

    a%20on%20Airbnb%20Android_0.pdf • Exploring RxJava 2 for Android • Jake Wharton https://www.youtube.com/watch?v=htIXKI5gOQU • Functional Reactive Programming with RxJava • Ben Christensen https://www.youtube.com/watch?v=_t06LRX0DV0&list=PLMacYHge0ewNw-VoFwXbNs9vCyvJumGnV • Learning RxJava for Android by example https://github.com/kaushikgopal/RxJava-Android-Samples • Fragmented Podcast: 004: The RxJava show with Dan Lew (Part 2) http://fragmentedpodcast.com/episodes/4/ • Reactivex.io: Documentation (Marbles!) http://reactivex.io/documentation/