Rx.Android

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Intro to Rx

  • What's Rx
  • Exercise 1: Explore some simple Rx operators

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Intro to Rx

The Observer pattern done right

ReactiveX is a combination of the best ideas from
the Observer pattern, the Iterator pattern, 

and functional programming

-- http://reactivex.io/

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Intro to Rx

  • Extends the observer pattern
  • Supports sequences of data and/or event
  • Compose sequences together declaratively using operators
  • Abstracts away: low-level threading, synchronization, thread-safety, concurrent data structures, and non-blocking I/O

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Aysnc/Push Iterator

single items multiple items
synchronous T getData() Iterable<T> getData()
asynchronous Future<T> getData() Observable<T> getData()
event Iterable (pull) Observable (push)
retrieve data T next() onNext(T)
discover error throws Exception onError(Exception)
complete !hasNext() onCompleted()

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Intro to Rx - Simple Observable

obs = Observable.just(1, 2, 3, 4, 5);
obs.subscribe(onNext, onError, onComplete);

1

2

3

4

5

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Intro to Rx - Simple Observable

obs.subscribe(new Action1< Integer >() {
    @Override
    public void call(String value) { /* on emition */ }
}, new Action1< Throwable >() {
    @Override
    public void call(Throwable throwable) { /* on error */ }
}, new Action0() {
    @Override
    public void call() { /* on complete */ }
});

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Observable.just(1, 2, 3, 4, 5)
          .map(new Func1< Integer, String >() {
              @Override
              public String call(Integer number) {
                  return number.toString();
              }
          });

1. Intro to Rx - Map Operator

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Intro to Rx - Map Operator

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Intro to Rx - Filter Operator

(Chaining)

Observable obs = Observable.just(1, 2, 3, 4, 5)
          .filter(new Func1<Integer, Boolean>() {
              @Override
              public Boolean call(Integer number) {
                  return number % 2 == 0;
              }
          })
          .map(new Func1< Integer, String >() {
              @Override
              public String call(Integer number) {
                  return number.toString();
              }
          });

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Intro to Rx

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

1. Intro to Rx

  • Observables are immutable
  • Compose functions into processing chains
  • Avoid callback hell
  • Structured code, feels like the right way!

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 1: Intro to Rx

git clone git@github.com:3pillarlabs/rx_android_workshop.git
cd rx_android_workshop
git checkout mb1
git checkout -b mb1
  • Explore the ExampleUnitTest class
  • Rewrite the "testObservable" method using TestSubscriber

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

2. Lambda expression

"... they provide a clear and concise way to represent one method interface using an expression ... "

-- Java 8

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

2. Lambda expression

  • There's no Java 8 support for Android ...
  • ... but there's Retrolambda: backport of Java 8's lambda expressions to Java 7, 6, 5

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

2. Lambda expression

/* no arguments, single statement */  () -> 42
/* one argument */                    number -> number * 2
/* multiple arguments */              (i, j) -> i * j
/* multiple arguments types */        (int i, long j) -> i * j

/* multiple statements */
(int i, long j) -> { long result = i * j; return result; }

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

2. Less code using with lambdas

Observable.just(1, 2, 3, 4, 5)
          .map(new Func1< Integer, String >() {
              @Override
              public String call(Integer number) {
                  return number.toString();
              }
          });

becomes

Observable.just(1, 2, 3, 4, 5)
          .map(i -> i.toString());

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

2. Lambda expressions - Method Reference

obs = Observable.just("1", "2", "3")

/* lambda enhanced code */
obs.map(nr -> Integer.parseInt(nr))

/* using method reference */
obs.map(Integer::parseInt)
  • sometimes, a lambda expression does nothing but call an existing method

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 2: Less code with lambdas

git add -A && git commit -m "progress"
git checkout mb2
git checkout -b mb2

Neat huh?! Let's get to work

  • Play around with the IDE features to expand/replace lambda expressions
  • Write a new test for transforming Integers into Strings

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 3: Explore Rx Operators

git add -A && git commit -m "progress"
git checkout mb3
git checkout -b mb3
  • Please make all tests in ExploreSimpleOperatorsTest pass using only Rx operators!
  • Fix the tests sequentially

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

4. Reactive HTTP with Retrofit

"Retrofit turns your HTTP API into a Java interface"

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

4. Reactive HTTP with Retrofit

public interface OmdbApi {
    @GET("/?y=&plot=short&r=json")
    Observable< OmdbMovie > findByTitle(@Query("t") String t);
}
...
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://www.omdbapi.com")
        .build();

OmdbApi api = retrofit.create(OmdbApi.class);

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 4: Reactive HTTP with Retrofit

git add -A && git commit -m "progress"
git checkout mb4
git checkout -b mb4
  • Explore & execute tests for the provided API

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 5: Easy networking with reactive streams

git add -A && git commit -m "progress"
git checkout mb5
git checkout -b mb5
  • Search movies by title using the api and display results in popup
  • Don't forget to add INTERNET permission to the manifest

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

5. Handle Errors

  • There's a runtime error in the current implementation. Please fix it!
  • Remember to implement the onError method for your subscriber!

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

5. Schedulers

  • By default, an Observable and the operators, will work on the same thread on which its the subscribe method is called
  • subscribeOn: Schedulers.computation(), Schedulers.io(), etc
  • observeOn: AndroidSchedulers.mainThread(), etc

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

6. RxBinding

  • Bind to your views and ui events in a reactive way
  • Use of flatMap and multithread 
git add -A && git commit -m "progress"
git checkout mb6
git checkout -b mb6

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

6. FlatMap

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

6. Multithread ?

RxTextView.textChanges(searchText)
          .flatMap(title -> omdbApi.searchByTitle(title))
          .subscribeOn(Schedulers.io());

RxTextView.textChanges(searchText)
          .flatMap(title -> omdbApi.searchByTitle(title)
                                   .subscribeOn(Schedulers.io()));

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 7: Unsubscribe

  • Fix memory leaks 
  1. Subscription.unsubscribe()
  2. CompositeSubscription 

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 7: RxLifecycle

git add -A && git commit -m "progress"
git checkout mb7
git checkout -b mb7
  • Allow for automatic completion of sequences based on Activity or Fragment lifecycle events - useful in Android, as incomplete subscriptions can cause memory leaks

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 8: Optimal "hot search"

git add -A && git commit -m "progress"
git checkout mb8
git checkout -b mb8
  • MovieSerchService#last_title_should_match_search
    should pass

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. Optimal "hot search"

To improve:

  • avoid too many requests
  • handle errors
  • responses are not ordered

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. Limiting throughput

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. Handling errors

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. Handling errors

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. flatMap = merge(map)

  • non blocking
  • fail fast

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. flatMap multithread

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. concatMap

  • Order is guaranteed
  • Blocking!

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. concatMap

 

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. switchMap

  • Subscribe for the last only
  • Unsubscribe/cancel the previous

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

8. switchMap

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 9: Implement a RxBiding

git add -A && git commit -m "progress"
git checkout mb9
git checkout -b mb9
  • Use RxListPopupWindow instead of listener

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

10. DB Integration

  • SQLBrite - A lightweight wrapper around SQLiteOpenHelper and ContentResolver which introduces reactive stream semantics to queries.

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

10. DB Integration

...
@Inject
BriteDatabase db;
...
db.createQuery(table_name, query, params)
  • Besides the sqlQuery & params, the method takes an additional parameter of table(s) on which to listen for changes
  • Subscribe to the returned Observable which will immediately notify with a Query to run
  • When you insert, update, or delete data, any subscribed queries will update with the new data instantly.

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

10. DB Integration

  • You shall use MovieItemDao
  • Let's have a quick look at the code

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 10: Populate view from DB

git add -A && git commit -m "progress"
git checkout mb10
git checkout -b mb10
  • Show DB data in the recycler view

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 11: Save movie into DB

git add -A && git commit -m "progress"
git checkout mb11
git checkout -b mb11
  • Request detailed movie
  • Transform it into ContentValues (MovieItem)
  • Save into DB using the DAO

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 12: Materilize

Wrap events and errors

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 12: Materilize

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 12: Backpressure

When Producer is faster than consumer

February 19, 2016 | GitHub: 3pillarlabs / rx_android_workshop

Exercise 12: Demo

git add -A && git commit -m "progress"
git checkout mb12
git checkout -b mb12

Mobos RxAndroid workshop

By Karoly Szanto

Mobos RxAndroid workshop

  • 367
Loading comments...

More from Karoly Szanto