1. Functional Reactive Programming on
Android
Sam Lee
2014/11/22 @Mosut x Taina.py x FP
http://misgod.github.io/Slide-FRP-Android/ 第 1 ⾴
2. About Me
Sam Lee (misgod.tw@gmail.com)
A software engineer lives in Tainan
Work for htc
Most used Clojure, Scala and Java
Interested in Functional Programming
Interested in Machine Learning and Data Analyst
·
·
·
·
·
http://misgod.github.io/Slide-FRP-Android/ 第 2 ⾴
3. What Is Functional Reactive Programming
A style of programming based on two key ideas: continuous time-varying behaviors, and
event-based reactivity
Try it
aObservable.map(x -> x*x) //Square
.reduce((a, b) -> a+b) //Sum
.subscribe(x -> println(x)); //Show
http://misgod.github.io/Slide-FRP-Android/ 第 3 ⾴
4. Why Functional Reactive Programming
Writing concurrent programs · correct is di2cult.
You can transform & compose asynchronous operations.
High-level abstractions
Standard error handling
·
·
·
http://misgod.github.io/Slide-FRP-Android/ 第 4 ⾴
6. Introduce to RxJava
https://github.com/ReactiveX/RxJava
RxJava is a JVM implementation of Reactive Extensions
RxJava extends Observer pattern to support data/event and compose operators in
abstract.
Built by NetBix
Support Java 6+ & Android 2.3+
Java 8 lambda support
·
·
·
·
·
http://misgod.github.io/Slide-FRP-Android/ 第 6 ⾴
7. Asynchronous sequences of multiple items
SINGLE ITEMS MULTIPLE ITEMS
synchronous T getData() Iterable<T> getData()
asynchronous Future<T> getData() Observable<T> getData()
http://misgod.github.io/Slide-FRP-Android/ 第 7 ⾴
8. Observable is "dual" to Iterable
EVENT ITERABLE (PULL) OBSERVABLE (PUSH)
retrieve data T next() onNext(T)
discover error throws Exception onError(Exception)
complete !hasNext() onCompleted()
http://csl.stanford.edu/~christos/pldi2010.Gt/meijer.duality.pdf
http://misgod.github.io/Slide-FRP-Android/ 第 8 ⾴
35. Combining Observables - merge
ObservableString lower = Observable.from(new String[]{a, b, c});
ObservableString upper = Observable.from(new String[]{A, B, C});
Observable.merge(lower,upper).subscribe(System.out::println);
/* Or */
lower.mergeWith(upper).subscribe(System.out::println);
a
b
A
c
B
C
http://misgod.github.io/Slide-FRP-Android/ 第 35 ⾴
37. Combining Observables - startWith
ObservableString lower = Observable.from(new String[]{a, b, c});
ObservableString upper = Observable.from(new String[]{A, B, C});
lower.startWith(upper).subscribe(System.out::println);
A
B
C
a
b
c
http://misgod.github.io/Slide-FRP-Android/ 第 37 ⾴
41. Threading
observeOn
specify on which Scheduler a Subscriber should observe the Observable
subscribeOn
specify which Scheduler an Observable should use when its subscription is invoked
https://github.com/ReactiveX/RxJava/wiki/Scheduler
http://misgod.github.io/Slide-FRP-Android/ 第 41 ⾴
44. Subjects - How to use
Subscriber ----- Observable
PublishSubjectInteger subject = PublishSubject.create();
//Observable
subject.map(x - x*x)
.subscribe(o - println(o));
subject.map(x - x+1)
.subscribe(o - println(o));
//Subscriber
subject.onNext(11);
subject.onNext(11);
subject.onCompleted();
Masking a Subject as an Observable - aSubject.· asObservable()
http://misgod.github.io/Slide-FRP-Android/ 第 44 ⾴
45. Hot and Cold Observables
A “cold” Observable waits to emitting items until
observer subscribes , and so an observer can see the
whole sequenceg.
·
A “hot” Observable may begins emitting items as soon
as it is created.
·
http://misgod.github.io/Slide-FRP-Android/ 第 45 ⾴
47. About Android Development
Developing a robust app is painful
Developing a good UX app is painful
Thread, Executor, Handler, AsyncTask, Loader ...
RxJava can mitigate your pain
RetroGt supports methods with a return type of rx.Observable
·
life cycle, async, event, state, threading, - error handling
·
- interactive, realtime, smooth, animation
·
·
·
@GET(/user/{id}/photo)
ObservablePhoto getUserPhoto(@Path(id) int id);
http://misgod.github.io/Slide-FRP-Android/ 第 47 ⾴
48. RxAndroid
Android speciGc bindings for RxJava.
https://github.com/- ReactiveX/RxAndroid
Scheduler on main UI thread or a given Android Handler thread.
AndroidSchedulers
HandlerThreadScheduler
-
-
Reactive components for common Android use cases and UI widgets
·
·
·
AndroidObservable
ViewObservable
-
-
Don't forget to unsubscribe to avoid memory leak!
http://misgod.github.io/Slide-FRP-Android/ 第 48 ⾴
50. Case 1 - Say Hello to Callback Hell
/* API */
void getFromServer(String key, Action1String callback);
void getFromDB(String key, Action1String callback);
/* Code */
btnClick.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
getFromDB(myid, new Action1String() {
public void call(String s) {
getFromServer(s, new Action1String() {
public void call(final String s) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(context, s, LENGTH_LONG).show();
}
});
/* ... a lot of }) ... */
http://misgod.github.io/Slide-FRP-Android/ 第 50 ⾴
51. Case 1 - Say Hello to Callback Hell
Using Lambda expression
btnClick.setOnClickListener(view -
getFromDB(myid,
s - getFromServer(s,
x - runOnUiThread(
() - Toast.makeText(context, x, LENGTH_LONG).show()))));
· Shorter but not easy to read
http://misgod.github.io/Slide-FRP-Android/ 第 51 ⾴
52. Case 1 - Say Goodbye to Callback Hell
Using rx.Observable
/* API */
ObservableString getFromServer(String key);
ObservableString getFromDB(String key);
/* Code */
ViewObservable.clicks(btnClick)
.map(x - myid)
.observeOn(Schedulers.io())
.flatMap(this::getFromDB)
.flatMap(this::getFromServer)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(x - Toast.makeText(context, x, LENGTH_LONG).show());
http://misgod.github.io/Slide-FRP-Android/ 第 52 ⾴
53. Case 2 - All In One search
Requirements
A search engine includes google/yahoo/1. bing search results.
2. Should search diNerent engines in parallel
3. Retry 3 times when search fail
4. remove redundant url
ObservableSearchResult g = googleSearch.search(keyword).retry(3);
ObservableSearchResult b = bingSearch.search(keyword).retry(3);
ObservableSearchResult y = yahooSearch.search(keyword).retry(3);
Observable.merge(g, b, y)
.distinct(site - site.url)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(site - appendDataForUI() ,
err - errorhandle(err));
http://misgod.github.io/Slide-FRP-Android/ 第 53 ⾴
54. Case 3 - A simple EventBus
PublishSubjectObject subject = PublishSubject.create(); //Global Singleton
//...In Class A...
subject.filter(x - x instanceof DataUpdateAction)
.subscribe( x - ... doSomething ...);
//...In Class B...
subject.filter(x - x instanceof DeleteAction)
.subscribe( x - ... doSomething ...);
//...In Class C...
subject.filter(x - x instanceof RefreshAction)
.subscribe( x - ... doSomething ...);
subject.onNext(aDataUpdateAction);
subject.onNext(aDataUpdateAction;
subject.onNext(aRefreshAction);
http://misgod.github.io/Slide-FRP-Android/ 第 54 ⾴
56. Conclusion
Functional Reactive makes async/state design 1. straightforward.
2. RxJava is not just a library.
3. The most important is Functional Reactive Thinking.
4. Try It in your next project!
http://misgod.github.io/Slide-FRP-Android/ 第 56 ⾴