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

Observing RxJava on Android

Observing RxJava on Android

Everyone wants smooth, responsive, and robust apps. Yet asynchronous programming on Android leaves a lot to be desired. RxJava brings the Functional Reactive Programming paradigm to Java, making concurrency easy and enjoyable!

This talk will discuss the fundamentals and benefits of RxJava on Android, and help ease the learning curve of the FRP paradigm. See how to take advantage of Observables and Subscribers to keep your apps fast and reliable.

Michael Torres

May 09, 2015
Tweet

More Decks by Michael Torres

Other Decks in Programming

Transcript

  1. Apps React App Taps Keypresses Sensor updates Network Responses ….

    Update UI Change state Load data Save data ….
  2. Events Click events Text change events Network Response events Tweet

    events Sign in events … endless possibilities
  3. Time Tweet 1 Tweet 2 Tweet 3 Event Stream [

    ] Tweet 1 Tweet 2 Tweet 3 , ,
  4. Event Stream Operate on stream like an array Time Tweet

    1 Tweet 2 Tweet 3 Filter by HashTag Time Tweet 2
  5. Normally we pull items we need and work on them.

    The Rx way we push items and then work on them
  6. Observable Emit 0 or more items over time Knows if

    and when to complete Emit errors if necessary
  7. Create with Lambdas Observable.create(new OnSubscribe<String>() { @Override public void call(Subscriber<?

    super String> subscriber) { subscriber.onNext("Hello, World!"); } }); Observable.create(subscriber -> subscriber.onNext("Hello, World!"));
  8. Observable.create( subscriber -> { try { for (String filePath :

    getFilePaths()) { File file = expensiveFileOperation(filePath); subscriber.onNext(file); } subscriber.onCompleted(); } catch (Exception e) { subscriber.onError(e); } }); Create
  9. Observable.create( subscriber -> { try { for (String filePath :

    getFilePaths()) { File file = expensiveFileOperation(filePath); subscriber.onNext(file); } subscriber.onCompleted(); } catch (Exception e) { subscriber.onError(e); } }); Create
  10. Observable.create( subscriber -> { try { for (String filePath :

    getFilePaths()) { File file = expensiveFileOperation(filePath); subscriber.onNext(file); } subscriber.onCompleted(); } catch (Exception e) { subscriber.onError(e); } }); Create
  11. Observable.create( subscriber -> { try { for (String filePath :

    getFilePaths()) { File file = expensiveFileOperation(filePath); subscriber.onNext(file); } subscriber.onCompleted(); } catch (Exception e) { subscriber.onError(e); } }); Create
  12. Subscriber Subscriber<Integer> mySubscriber = new Subscriber<Integer>() { @Override public void

    onCompleted() { Log.i(TAG, "Finished"); } @Override public void onError(Throwable e) { Log.e(TAG, "Error occurred", e); } @Override public void onNext(Integer i) { Log.i(TAG, "Received:" + i); } };
  13. Subscriber Integer[] numbers = {1, 2, 3}; Observable.from(numbers) .subscribe(mySubscriber); Subscriber<Integer>

    mySubscriber = new Subscriber<Integer>() { @Override public void onCompleted() { Log.i(TAG, "Finished"); } @Override public void onError(Throwable e) { Log.e(TAG, "Error occurred", e); } @Override public void onNext(Integer i) { Log.i(TAG, "Received:" + i); } };
  14. Subscriber Received: 1 Received: 2 Received: 3 Finished Subscriber<Integer> mySubscriber

    = new Subscriber<Integer>() { @Override public void onCompleted() { Log.i(TAG, "Finished"); } @Override public void onError(Throwable e) { Log.e(TAG, "Error occurred", e); } @Override public void onNext(Integer i) { Log.i(TAG, "Received:" + i); } }; Integer[] numbers = {1, 2, 3}; Observable.from(numbers) .subscribe(mySubscriber);
  15. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Observable.interval(3, TimeUnit.SECONDS) .subscribe(new

    Action1<Long>() { @Override public void call(Long interval) { } }); } Memory Leak // Leaking context
  16. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); intervalSubscription = Observable.interval(3,

    TimeUnit.SECONDS) .subscribe(new Action1<Long>() { @Override public void call(Long interval) { } }); } Subscription Subscription intervalSubscription; // Leaking context
  17. Transform via Map Movie myMovie = new Movie(); Observable.just(myMovie) .map(movie

    -> movie.getActors()) .subscribe(actors -> "List of actors");
  18. Movie transformed to List<Actor> Movie myMovie = new Movie(); Observable.just(myMovie)

    .map(movie -> movie.getActors()) .subscribe(actors -> "List of actors"); Transform via Map
  19. Transform via FlatMap Movie myMovie = new Movie(); Observable.just(myMovie) .flatMap(movie

    -> Observable.from(movie.getActors())) .subscribe(actor -> "Actor " + actor.getName());
  20. Movie myMovie = new Movie(); Observable.just(myMovie) .flatMap(movie -> Observable.from(movie.getActors())) .subscribe(actor

    -> "Actor " + actor.getName()); Movie transformed to multiple Actor items Transform via FlatMap
  21. Observable<Flight> flightObservable = fetchFlight(flightId); Observable<Hotel> hotelObservable = fetchHotel(hotelId); Observable.zip(flightObservable, hotelObservable,

    (flight, hotel) -> { return new TravelInfo(flight, hotel); }) .subscribe(info -> "Got all travel info"); Combining via Zip
  22. Fetching Files Fetch all folders via user id Fetch all

    folder’s files via folder id Collect every file from every folder
  23. Observable.just(userId) .flatMap(userId -> fetchFolders(userId)) .map(folder -> folder.getId()) .flatMap(folderId -> fetchFiles(folderId))

    .toList() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(files -> "Got all files"); Fetching Files
  24. Observable.just(userId) .flatMap(userId -> fetchFolders(userId)) .map(folder -> folder.getId()) .flatMap(folderId -> fetchFiles(folderId))

    .toList() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(files -> "Got all files"); Fetching Files
  25. Observable.just(userId) .flatMap(userId -> fetchFolders(userId)) .map(folder -> folder.getId()) .flatMap(folderId -> fetchFiles(folderId))

    .toList() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(files -> "Got all files"); Fetching Files
  26. Observable<Boolean> emailObservable = WidgetObservable.text(emailTextField) .map(textChange -> isValidEmail(textChange.text())); Observable<Boolean> passwordObservable =

    WidgetObservable.text(passwordTextField) .map(textChange -> isValidPassword(textChange.text())); Func2<Boolean, Boolean, Boolean> combineFunction = (validEmail, validPassword) -> validEmail && validPassword; Form Validation
  27. Observable<Boolean> emailObservable = WidgetObservable.text(emailTextField) .map(textChange -> isValidEmail(textChange.text())); Observable<Boolean> passwordObservable =

    WidgetObservable.text(passwordTextField) .map(textChange -> isValidPassword(textChange.text())); Func2<Boolean, Boolean, Boolean> combineFunction = (validEmail, validPassword) -> validEmail && validPassword; Form Validation
  28. Observable<Boolean> emailObservable = WidgetObservable.text(emailTextField) .map(textChange -> isValidEmail(textChange.text())); Observable<Boolean> passwordObservable =

    WidgetObservable.text(passwordTextField) .map(textChange -> isValidPassword(textChange.text())); Func2<Boolean, Boolean, Boolean> combineFunction = (validEmail, validPassword) -> validEmail && validPassword; Form Validation
  29. Blocking Observable<String> myObservable = Observable.just("one", "two", "three") .skip(1) .take(1) .observeOn(AndroidSchedulers.mainThread())

    .subscribeOn(Schedulers.newThread()); String item = myObservable.toBlocking().single(); assertEquals(item, "two");
  30. Blocking Observable<String> myObservable = Observable.just("one", "two", "three") .skip(1) .take(1) .observeOn(AndroidSchedulers.mainThread())

    .subscribeOn(Schedulers.newThread()); String item = myObservable.toBlocking().single(); assertEquals(item, "two");
  31. TestSubscriber TestSubscriber<String> subscriber = new TestSubscriber<>(); Observable.range(0, 3) .map(i ->

    String.valueOf(i)) .subscribe(subscriber); subscriber.assertReceivedOnNext(Arrays.asList("0", "1", "2")); subscriber.assertNoErrors(); subscriber.assertTerminalEvent(); subscriber.assertUnsubscribed();
  32. TestSubscriber TestSubscriber<String> subscriber = new TestSubscriber<>(); Observable.range(0, 3) .map(i ->

    String.valueOf(i)) .subscribe(subscriber); subscriber.assertReceivedOnNext(Arrays.asList("0", "1", "2")); subscriber.assertNoErrors(); subscriber.assertTerminalEvent(); subscriber.assertUnsubscribed();
  33. TestSubscriber TestSubscriber<String> subscriber = new TestSubscriber<>(); Observable.range(0, 3) .map(i ->

    String.valueOf(i)) .subscribe(subscriber); subscriber.assertReceivedOnNext(Arrays.asList("0", "1", "2")); subscriber.assertNoErrors(); subscriber.assertTerminalEvent(); subscriber.assertUnsubscribed();