RxJava on Android

Post on 16-Jan-2017

443 views 1 download

Transcript of RxJava on Android

RxJava RxAndroid

VIVINT, October 2015

Declarative vs. Imperative Programming

➤ Imperative Programming: telling the machine how to do something, and as a result what you want to happen will happen.

➤ Declarative Programming: telling the machine what you would like to happen, and let the computer figure out how to do it.

var numbers = [1,2,3,4,5] var doubled = []

for(var i = 0; i < numbers.length; i++) { var newNumber = numbers[i] * 2 doubled.push(newNumber) } console.log(doubled) //=> [2,4,6,8,10]

var numbers = [1,2,3,4,5] var total = 0

for(var i = 0; i < numbers.length; i++) { total += numbers[i] } console.log(total) //=> 15

var numbers = [1,2,3,4,5] var doubled = numbers.map(function(n) { return n * 2 }) console.log(doubled) //=> [2,4,6,8,10]

var numbers = [1,2,3,4,5]

var total = numbers.reduce(function(sum, n) { return sum + n }); console.log(total) //=> 15

Think about spreadsheets A cell does not represent a value, but a potential stream of values.

That stream can be split into many streams, combined or fed into other streams.

There are high-order functions that can consume these streams: ‘AVERAGE’, ‘SUM’,’SUMIF’,’POWER’, etc…

Functional Reactive Programming

Savings Percent 0.2 Monthly Wages 1600Hourly Wage 10 Annual Wages 19200Hours Worked/Wk 40 Annual Savings 3840Weekly Wages 400

Savings Percent 0.4 Monthly Wages 3200Hourly Wage 20 Annual Wages 38400Hours Worked/Wk 40 Annual Savings 15360Weekly Wages 800

What is RxJava?

➤ Observables & Subscribers

➤ High-order functions

➤ Schedulers

Observer Contract

Observable.just(1,2,3,4,5) .subscribe(new Subscriber<Integer>() { @Override public void onCompleted() { Log.d("Test", "sequence completed"); }

@Override public void onError(Throwable e) { Log.e("Test", "got error: " + e.getMessage()); }

@Override public void onNext(Integer integer) { Log.d("Test", "got int: " + integer); } });

The contract is very simple: onNext,onError,onCompleted

High-order functions

➤ filter

➤ map

➤ cast

➤ buffer

➤ debounce

➤ merge

➤ zip

➤ combineLatest

➤ flatMap

A few common examples:

Filter

Map

Cast

Buffer

Debounce

Merge

Zip

CombineLatest

FlatMap

Schedulers

➤ computation - for computation work

➤ immediate - current thread

➤ io - IO-bound work

➤ newThread - new thread for each unit

➤ test - useful for debugging

➤ trampoline - current thread, after current work

➤ AndroidSchedulers.mainThread (RxAndroid)

Consistent with the purpose of the high-order functions, RxJava’s schedulers remove the concern of how code gets run on different threads and allows the developer to simply declare which scheduler should run which units of work.

Example Scheduler Usage Observable .just(1) .delay(10, TimeUnit.SECONDS, Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<Integer>() { @Override public void onCompleted() {

}

@Override public void onError(Throwable e) {

}

@Override public void onNext(Integer integer) { Log.d("Test", "this is on the main thread!"); } });

RxJava + Schedulers vs AsyncTask

➤ Easier to use ➤ More effective error handling (built-in)

➤ Use of high-order functions

➤ Easily cancelable

➤ Easily retry-able ➤ Testable ➤ Greater control over concurrency

➤ AsyncTask has just 2 options, ThreadPoolExecutor or not and you can’t control what thread the onPostExecute fires on.

representativeApi.representativesByZipCode(zipCode) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .toList() .retry(2) .subscribe(onRepresentativesReceived());

A compelling RxJava Example

RxJava on Android

➤ RxAndroid - minimum base

➤ RxLifecycle - easy lifecycle handling

➤ RxBinding - easily create observables from Android UI widgets

As of this writing, RxAndroid has had a lot of recent changes. Formerly, it contained nearly every useful thing required to build RxJava apps in Android. It has now been broken up into several constituent pieces.

RxLifecycle

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Observable .interval(1, TimeUnit.SECONDS, Schedulers.io()) .compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Long>() { @Override public void call(Long aLong) { Log.d("Test", "logging stuff until destroyed"); } });

}

Makes it easy to keep updates happening within safe timeframes

RxBinding

Observable<Double> hourlyWageObservable = RxTextView.textChanges(_hourlyWage) .map(new Func1<CharSequence, Double>() { @Override public Double call(CharSequence charSequence) { try { return Double.parseDouble(charSequence.toString()); } catch (NumberFormatException e) { return 0D; } } });

Makes it easy to create Observables from Android UI widgets

RxJava Challenges

➤ No lambdas on Android(requires Java 8)

➤ Lots of extra code, but nearly negated by solid auto-complete tools

➤ Can be overcome with retrolambda but it can be fickle

➤ Steep learning curve

➤ Easy traditional solutions can seem difficult to perform with RxJava at first

Sample Project

➤ RxAndroid-Sample

➤ Use of RxAndroid, RxLifecycle, RxBinding

➤ Use of Retrofit with RxJava

➤ Example of converting non-RxJava code to work with RxJava

➤ More…

Final Words

RxJava is not about writing less code or doing things that were impossible before. It’s about focusing more lines of code toward your application’s actual objectives. It helps with this by removing all the tedious, generic coding that we have to do every day: allowing the solved problems stay solved while we move on to more important things. When we can reduce the number of wrote, for-loop collection manipulation routines we can do in our sleep we can spend more time thinking about and solving the real problems.