An exploration into RxJava on Android for the experienced, yet uninitiated software engineer. This presentation explores Declarative vs Imperative programming paradigms and expands the discussion into Functional Reactive Programming. It explains the benefits of the observer contract, high-order functions, and schedulers available in RxJava. It also explains the purpose of the Android integration libraries: RxAndroid, RxLifecycle, and RxBindings.
2. 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
3. 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 1600
Hourly Wage 10 Annual Wages 19200
Hours Worked/Wk 40 Annual Savings 3840
Weekly Wages 400
Savings Percent 0.4 Monthly Wages 3200
Hourly Wage 20 Annual Wages 38400
Hours Worked/Wk 40 Annual Savings 15360
Weekly Wages 800
4. What is RxJava?
➤ Observables & Subscribers
➤ High-order functions
➤ Schedulers
5. 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
6. High-order functions
➤ filter
➤ map
➤ cast
➤ buffer
➤ debounce
➤ merge
➤ zip
➤ combineLatest
➤ flatMap
A few common examples:
16. 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.
17. 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!");
}
});
18. 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
19. 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.
20. 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
21. 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
22. 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
25. 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…
26. 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.