Reactive Android: RxJava and beyond - Fabio Tiriticco - Codemotion Amsterdam 2016
RxJava on Android
-
Upload
dustin-graham -
Category
Engineering
-
view
433 -
download
1
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
Useful compatible libraries
➤ SqlBrite
➤ Retrofit - example
➤ RxPreferences
Testing
➤ One Interesting Article
➤ Another Interesting Article
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.