Slide 1

Slide 1 text

RxJava & RxAndroid Bringing Reactive to the Android world

Slide 2

Slide 2 text

Hi! google.com/+CosminStefan [email protected] http://silverbit.ro

Slide 3

Slide 3 text

Contents Can I use ReactiveX in Java & Android? RxJava - how does it look like? What can I do with it in Android? What should I keep in mind?

Slide 4

Slide 4 text

RxJava - What is it this about? Java implementation of Reactive Extensions Zero dependencies Relatively small footprint (<800KB) Stable (1.1.0 - December 2015) Support for Scala, Groovy, Clojure, Kotlin

Slide 5

Slide 5 text

RxAndroid Android specific bindings for RxJava Driven by Jake Wharton Very thin layer above RxJava

Slide 6

Slide 6 text

A quick detour

Slide 7

Slide 7 text

Lambda Expressions Pass functionality as argument Short implementation of single-method anonymous classes Type inference (argumentList) -> { /* code */ }

Slide 8

Slide 8 text

Lambda Expressions - Examples mTextView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // perform action } }); new Thread(new Runnable() { @Override public void run() { System.out.println("Hello World!"); } }); mTextView.setOnClickListener(v -> { // perform action }); new Thread(() -> { System.out.println("Hello World!"); });

Slide 9

Slide 9 text

Retrolambda Java 8 Lambda functionality down to Java 5 Gradle integration for Android Editing support in Android Studio

Slide 10

Slide 10 text

Let’s get to business

Slide 11

Slide 11 text

RxJava - Starting simple Observable observable = Observable.just("Hello, GDG Bucharest!");

Slide 12

Slide 12 text

RxJava - Starting simple (2) Observable observable = Observable.just("Hello, GDG Bucharest!"); observable.subscribe(new Observer() { @Override public void onNext(String value) { System.out.println(value); } @Override public void onCompleted() { System.out.println("The End!"); } @Override public void onError(Throwable e) { System.err.println("Ooops, I did it again!"); } });

Slide 13

Slide 13 text

RxJava - Making it simpler We can just specify a subset of the actions observable.subscribe(onNextAction, onErrorAction, onCompleteAction); observable.subscribe(onNextAction, onErrorAction); observable.subscribe(onNextAction); public interface Action1 { public void call(T value); }

Slide 14

Slide 14 text

RxJava meets lambda Observable.just("Hello, GDG Bucharest!");

Slide 15

Slide 15 text

RxJava meets lambda Observable.just("Hello, GDG Bucharest!") .subscribe(new Action1() { @Override public void call(String value) { System.out.println(value); } });

Slide 16

Slide 16 text

RxJava meets lambda Observable.just("Hello, GDG Bucharest!") .subscribe(new Action1() { @Override public void call(String value) { System.out.println(value); } }); Observable.just("Hello, GDG Bucharest!") .subscribe(s -> System.out.println(s))

Slide 17

Slide 17 text

Transforming Observable.just("Hello, GDG Bucharest!") .map(new Func1() { @Override public Integer call(String s) { return s -> s.hashCode(); } }) .subscribe(new Action1() { @Override public void call(Integer hash) { System.out.println("The hash is: " + hash) } });

Slide 18

Slide 18 text

Transforming Observable.just("Hello, GDG Bucharest!") .map(new Func1() { @Override public Integer call(String s) { return s -> s.hashCode(); } }) .subscribe(new Action1() { @Override public void call(Integer hash) { System.out.println("The hash is: " + hash) } }); Observable.just("Hello, GDG Bucharest!") .map(s -> s.hashCode()) .subscribe(hash -> System.out.println("The hash is: " + hash));

Slide 19

Slide 19 text

Taking it to the next step Observable.just("Hello, GDG Bucharest!") .map(s -> s + ";Hello, World!") .flatMap(s -> { String[] pieces = s.split(";"); return Observable.from(pieces); }) .map(s -> s + "!!") .subscribe(s -> System.out.println(s));

Slide 20

Slide 20 text

Taking it to the next step Observable.just("Hello, GDG Bucharest!") .map(s -> s + ";Hello, World!") .flatMap(s -> { String[] pieces = s.split(";"); return Observable.from(pieces); }) .map(s -> s + "!!") .subscribe(s -> System.out.println(s)); Outputs: Hello, GDG Bucharest!!! Hello, World!!!

Slide 21

Slide 21 text

RxJava - Creating a cold observable Observable.create(new Observable.OnSubscribe() { @Override public void call(Subscriber subscriber) { // Do some more stuff subscriber.onNext("Hello, GDG Bucharest!"); subscriber.onCompleted(); } });

Slide 22

Slide 22 text

RxJava - Creating a cold observable Observable.create(new Observable.OnSubscribe() { @Override public void call(Subscriber subscriber) { // Do some more stuff subscriber.onNext("Hello, GDG Bucharest!"); subscriber.onCompleted(); } }); Observable.create(subscriber -> { // Do some more stuff subscriber.onNext("Hello, GDG Bucharest!"); subscriber.onCompleted(); });

Slide 23

Slide 23 text

Schedulers Mechanism to switch the threads on which steps get executed Schedulers.computation(); Schedulers.io(); Schedulers.immediate(); AndroidSchedulers.mainThread();

Slide 24

Slide 24 text

Schedulers - Power overwhelming public Observable loadImage(String url);

Slide 25

Slide 25 text

Schedulers - Power overwhelming public Observable loadImage(String url); ... loadImage(testUrl) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(bitmap -> mImageView.setImageBitmap(bitmap));

Slide 26

Slide 26 text

So, what does it do for me?

Slide 27

Slide 27 text

Event Bus - the idea Decouple event emitters and consumers Steps: Subject + Subscriber Subject lives “forever” Anyone can post events Observers subscribe when needed

Slide 28

Slide 28 text

Event Bus - How? Subjects to the rescue class RxBus { private final Subject mBus = new SerializedSubject<>(PublishSubject.create()); public void post(MyEvent e) { mBus.onNext(e); } public Observable toObserverable() { return mBus.asObservable(); } }

Slide 29

Slide 29 text

Event Bus - How? Sending events: rxBus.post(new MyEvent());

Slide 30

Slide 30 text

Event Bus - How? Sending events: rxBus.post(new MyEvent()); Listening for events: rxBus.toObserverable() .subscribe(event -> { // do something with the event });

Slide 31

Slide 31 text

Instant search throttling - the idea Wait until text has “stabilized” Steps: Observable + Debounce operator Watcher for text change events on InputTextView Conversion to observable events Debounce for limiting

Slide 32

Slide 32 text

Instant search throttling - How? public Observable observableForTextViewChangeEvents(TextView tv); ... observableForTextViewChangeEvents(mTextView) // make sure it’s stable .debounce(400, TimeUnit.MILLISECONDS) // perform the search .map(textChangeEvent -> { return performSearch(textChangeEvent); }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) // and finally update the UI accordingly .subscribe(searchResults -> { updateUI(searchResults) });

Slide 33

Slide 33 text

Load both from cache and from network Quickly show preliminary results from cache Steps: Concat / Merge operator Create observables for both types of load Merge the results and handle in common way Cache prefetching - the idea

Slide 34

Slide 34 text

Cache prefetching - How? Observable cacheDataLoader = loadCacheData(); Observable freshDataLoader = loadFreshData();

Slide 35

Slide 35 text

Cache prefetching - How? Observable cacheDataLoader = loadCacheData(); Observable freshDataLoader = loadFreshData(); Observable.concat(cacheDataLoader, freshDataLoader) .observeOn(AndroidSchedulers.mainThread()) .subscribe( data -> { // Update the UI with the available data mAdapter.setNewData(data); });

Slide 36

Slide 36 text

Generic API / library - sync vs async Build a versatile API / library supporting both async or sync use Steps: Observable + subscribeOn()/observeOn() Expose Cold Observables (perform work upon subscription) Can be run either synchronously or asynchronously

Slide 37

Slide 37 text

Generic API - sync vs async // Perform task on the current thread mMyFancyApi.doFancyTask() .subscribe(result -> doSomething());

Slide 38

Slide 38 text

Generic API - sync vs async // Perform task on the current thread mMyFancyApi.doFancyTask() .subscribe(result -> doSomething()); // Perform task asynchronously mMyFancyApi.doFancyTask() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> doSomethingElse());

Slide 39

Slide 39 text

Retrofit and RxJava, sitting in a tree Simplify network calls to APIs Steps: Retrofit + Operators + subscribeOn()/observeOn() Use the Rx-aware Retrofit calls Run network calls on Schedulers.io() Chain processing Switch back to main thread for UI updates

Slide 40

Slide 40 text

Retrofit and RxJava, sitting in a tree mWebService.fetchPosts() // Split posts list to individual items .flatMap(posts -> Observable.from(posts)) // Process each item .doOnNext(post -> storeToLocalDatabase(post)) // Take just the last post .last() // Configure threads properly .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) // Handle final results .subscribe(post -> { updateUI(post); }, (error) -> { Log.e(TAG, "Network error!", error); } );

Slide 41

Slide 41 text

What to keep in mind

Slide 42

Slide 42 text

Android lifecycles Take Activity/Fragment lifecycle into account Care when outliving the bound components Unsubscribe when result not needed anymore RxLifecyle to the rescue “Lifecycle handling APIs for Android apps using RxJava”

Slide 43

Slide 43 text

Parting thoughts Can certainly simplify certain scenarios Power comes from chaining operations Thread switching easier Synchronization still an issues Not a silver bullet Don’t overuse - performance can become an issue

Slide 44

Slide 44 text

Rx enabled Projects https://github.com/square/retrofit - REST service wrapper https://github.com/jersey/jersey - REST service wrapper https://github.com/square/sqlbrite - Reactive database wrapper https://github.com/ReactiveX/RxNetty - Async network framework https://github.com/davidmoten/rtree - RTree implementation https://github.com/Netflix/Hystrix - Latency and fault tolerance library https://github.com/mulab/rx-realm - Mobile database system & many more....

Slide 45

Slide 45 text

Thank you! google.com/+CosminStefan [email protected] http://silverbit.ro

Slide 46

Slide 46 text

What’s next? http://reactivex.io/intro.html http://rxmarbles.com/ http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/ http://www.slideshare.net/allegrotech/rxjava-introduction-context https://github.com/kaushikgopal/RxJava-Android-Samples https://github.com/evant/gradle-retrolambda https://github.com/JakeWharton/RxBinding