57
Functional Reactive Programming on Android Sam Lee 2014/11/22 @Mosut x Taina.py x FP http://misgod.github.io/Slide-FRP-Android/ 第 1 ⾴

Functional Reactive Programming on Android

  • Upload
    sam-lee

  • View
    2.573

  • Download
    6

Embed Size (px)

DESCRIPTION

The original slide is here... http://misgod.github.io/Slide-FRP-Android Introduce to Functional Reactive Programming on Android with RxJava/RxAndroid.

Citation preview

Page 1: Functional Reactive Programming on Android

Functional Reactive Programming onAndroidSam Lee2014/11/22 @Mosut x Taina.py x FP

http://misgod.github.io/Slide-FRP-Android/ 第 1 ⾴

Page 2: Functional Reactive Programming on Android

About MeSam Lee ([email protected])

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 ⾴

Page 3: Functional Reactive Programming on Android

What Is Functional Reactive ProgrammingA style of programming based on two key ideas: continuous time-varying behaviors, andevent-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 ⾴

Page 4: Functional Reactive Programming on Android

Why Functional Reactive Programming

Writing concurrent programs correct is di�cult.·

You can transform & compose asynchronous operations.

High-level abstractions

Standard error handling

·

·

·

http://misgod.github.io/Slide-FRP-Android/ 第 4 ⾴

Page 5: Functional Reactive Programming on Android

Say Hello to Rx familyJava: RxJava

Scala: RxScala

Clojure: RxClojure

Groovy: RxGroovy

JRuby: RxJRuby

JavaScript: RxJS

C#: Rx.NET

C#(Unity): UniRx

C++: RxCpp

Ruby: Rx.rb

Python: RxPY

Kotlin: RxKotlin

·

·

·

·

·

·

·

·

·

·

·

·

http://misgod.github.io/Slide-FRP-Android/ 第 5 ⾴

Page 6: Functional Reactive Programming on Android

Introduce to RxJavahttps://github.com/ReactiveX/RxJava

RxJava is a JVM implementation of Reactive Extensions

RxJava extends Observer pattern to support data/event and compose operators inabstract.

Built by Net�ix

Support Java 6+ & Android 2.3+

Java 8 lambda support

·

·

·

·

·

http://misgod.github.io/Slide-FRP-Android/ 第 6 ⾴

Page 7: Functional Reactive Programming on Android

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 ⾴

Page 8: Functional Reactive Programming on Android

Observable is "dual" to IterableEVENT 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.�t/meijer.duality.pdf

http://misgod.github.io/Slide-FRP-Android/ 第 8 ⾴

Page 9: Functional Reactive Programming on Android

Observable & Observer

pushman.subscribe(new Action1<Integer>() {

@Override

public void call(Integer x) {

println("receive: " + x);

}

});

http://misgod.github.io/Slide-FRP-Android/ 第 9 ⾴

Page 10: Functional Reactive Programming on Android

Observer pattern

http://misgod.github.io/Slide-FRP-Android/ 第 10 ⾴

Page 11: Functional Reactive Programming on Android

Functional Reactive

http://misgod.github.io/Slide-FRP-Android/ 第 11 ⾴

Page 12: Functional Reactive Programming on Android

Lambda Expression

http://misgod.github.io/Slide-FRP-Android/ 第 12 ⾴

Page 13: Functional Reactive Programming on Android

OriginalaObservable.filter(new Func1<Integer, Boolean>() {

public Boolean call(Integer n) {

return n % 2 == 0;

}

})

.map(new Func1<Integer, Integer>() {

public Integer call(Integer n) {

return n * n;

}

})

.subscribe(new Action1<Integer>() {

public void call(Integer n) {

System.out.println(n);

}

});

WTF...·

http://misgod.github.io/Slide-FRP-Android/ 第 13 ⾴

Page 14: Functional Reactive Programming on Android

Java 8 lambda

aObservable.filter(n -> n % 2 == 0)

.map(n -> n * n)

.subscribe(System.out::println);

but ... no java8 on Davilk(Android)·

http://misgod.github.io/Slide-FRP-Android/ 第 14 ⾴

Page 15: Functional Reactive Programming on Android

RetrolambdaRetrolambda lets you run Java 8 code with lambda expressions and

method references on Java 7 or lower.

Retrolambda

Gradle plugin

·

https://github.com/orfjackal/retrolambda-

·

https://github.com/evant/gradle-retrolambda-

http://misgod.github.io/Slide-FRP-Android/ 第 15 ⾴

Page 16: Functional Reactive Programming on Android

Retrolambda

http://misgod.github.io/Slide-FRP-Android/ 第 16 ⾴

Page 17: Functional Reactive Programming on Android

rx.Observable

http://misgod.github.io/Slide-FRP-Android/ 第 17 ⾴

Page 18: Functional Reactive Programming on Android

Creating Observable - just

Observable<List<String>> ob = Observable.just(aList);

Observable<String> ob2 = Observable.just("Some String");

http://misgod.github.io/Slide-FRP-Android/ 第 18 ⾴

Page 19: Functional Reactive Programming on Android

Creating Observable - from

List<String> aList = ...;

Observable<String> ob = Observable.from(aList);

http://misgod.github.io/Slide-FRP-Android/ 第 19 ⾴

Page 20: Functional Reactive Programming on Android

Creating Observable - create

http://misgod.github.io/Slide-FRP-Android/ 第 20 ⾴

Page 21: Functional Reactive Programming on Android

Creating Observable - createob = Observable.create(subscriber -> {

try {

for (String s : aList) {

if (subscriber.isUnsubscribed())

return;

subscriber.onNext(s);

}

subscriber.onCompleted();

} catch (Exception e) {

subscriber.onError(e);

}

});

http://misgod.github.io/Slide-FRP-Android/ 第 21 ⾴

Page 22: Functional Reactive Programming on Android

Creating Observable ...

https://github.com/ReactiveX/RxJava/wiki/Creating-Observables

repeat( )

range( )

interval( )

timer( )

empty( )

error( )

·

·

·

·

·

·

http://misgod.github.io/Slide-FRP-Android/ 第 22 ⾴

Page 23: Functional Reactive Programming on Android

Transforming Observables - map

http://misgod.github.io/Slide-FRP-Android/ 第 23 ⾴

Page 24: Functional Reactive Programming on Android

Transforming Observables - mapObservable.range(0, 5)

.map(x -> toBinaryString(x*x))

.subscribe(s -> println(s),

err -> err.printStackTrace(),

() -> println("done"));

0

1

100

1001

10000

done

http://misgod.github.io/Slide-FRP-Android/ 第 24 ⾴

Page 25: Functional Reactive Programming on Android

Transforming Observables - flatmap

http://misgod.github.io/Slide-FRP-Android/ 第 25 ⾴

Page 26: Functional Reactive Programming on Android

Transforming Observables - flatmapObservable.range(1, 3)

.flatMap(x -> Observable.just(x).repeat(x))

.subscribe(System.out::println);

1

2

2

3

3

3

Observable is a Monad·

unit (return) ==> just

join (bind, >>=) ==> �atmap

-

-

http://misgod.github.io/Slide-FRP-Android/ 第 26 ⾴

Page 27: Functional Reactive Programming on Android

Transforming Observables - concatmap

http://misgod.github.io/Slide-FRP-Android/ 第 27 ⾴

Page 28: Functional Reactive Programming on Android

Filtering Observables

http://misgod.github.io/Slide-FRP-Android/ 第 28 ⾴

Page 29: Functional Reactive Programming on Android

Filtering ObservablesObservable.range(0, 10)

.filter(x -> (x % 2) == 0)

.subscribe(System.out::println);

0

2

4

6

8

http://misgod.github.io/Slide-FRP-Android/ 第 29 ⾴

Page 30: Functional Reactive Programming on Android

Filtering Observables

https://github.com/ReactiveX/RxJava/wiki/Filtering-Observables

distinct( )

�rst( )

take( )

skip( )

elementAt( )

sample( )

more...

·

·

·

·

·

·

·

http://misgod.github.io/Slide-FRP-Android/ 第 30 ⾴

Page 31: Functional Reactive Programming on Android

Aggregate Operators - reduce

http://misgod.github.io/Slide-FRP-Android/ 第 31 ⾴

Page 32: Functional Reactive Programming on Android

Aggregate Operators - reduceObservable.range(1, 10)

.reduce((a, b) -> a*b)

.subscribe(System.out::println);

3628800

http://misgod.github.io/Slide-FRP-Android/ 第 32 ⾴

Page 33: Functional Reactive Programming on Android

Aggregate Operators - concat

http://misgod.github.io/Slide-FRP-Android/ 第 33 ⾴

Page 34: Functional Reactive Programming on Android

Combining Observables - merge

http://misgod.github.io/Slide-FRP-Android/ 第 34 ⾴

Page 35: Functional Reactive Programming on Android

Combining Observables - mergeObservable<String> lower = Observable.from(new String[]{"a", "b", "c"});

Observable<String> 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 ⾴

Page 36: Functional Reactive Programming on Android

Combining Observables - startWith

http://misgod.github.io/Slide-FRP-Android/ 第 36 ⾴

Page 37: Functional Reactive Programming on Android

Combining Observables - startWithObservable<String> lower = Observable.from(new String[]{"a", "b", "c"});

Observable<String> 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 ⾴

Page 38: Functional Reactive Programming on Android

Combining Observables - zip

http://misgod.github.io/Slide-FRP-Android/ 第 38 ⾴

Page 39: Functional Reactive Programming on Android

Combining Observables - zipObservable<String> lower = Observable.from(new String[]{"a", "b", "c"});

Observable<String> upper = Observable.from(new String[]{"A", "B", "C"});

Observable.zip(lower, upper, Pair::create)

.map(pair -> pair.first +"_" +pair.second)

.subscribe(System.out::println);

a_A

b_B

c_C

http://misgod.github.io/Slide-FRP-Android/ 第 39 ⾴

Page 40: Functional Reactive Programming on Android

Error Handling

https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators

OnErrorResumeNext

OnErrorReturn

retry

·

·

·

http://misgod.github.io/Slide-FRP-Android/ 第 40 ⾴

Page 41: Functional Reactive Programming on Android

ThreadingobserveOnspecify on which Scheduler a Subscriber should observe the Observable

subscribeOnspecify 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 ⾴

Page 42: Functional Reactive Programming on Android

SubjectsA Subject = Subscriber + Observable

http://misgod.github.io/Slide-FRP-Android/ 第 42 ⾴

Page 43: Functional Reactive Programming on Android

Subjects

https://github.com/ReactiveX/RxJava/wiki/Subject

PublishSubject

BehaviorSubject

AsyncSubject

ReplaySubject

·

·

·

·

http://misgod.github.io/Slide-FRP-Android/ 第 43 ⾴

Page 44: Functional Reactive Programming on Android

Subjects - How to useSubscriber -----> Observable

PublishSubject<Integer> 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 ⾴

Page 45: Functional Reactive Programming on Android

Hot and Cold Observables

A “cold” Observable waits to emitting items untilobserver subscribes , and so an observer can see thewhole sequenceg.

·

A “hot” Observable may begins emitting items as soonas it is created.

·

http://misgod.github.io/Slide-FRP-Android/ 第 45 ⾴

Page 46: Functional Reactive Programming on Android

RxJava on Android

http://misgod.github.io/Slide-FRP-Android/ 第 46 ⾴

Page 47: Functional Reactive Programming on Android

About Android DevelopmentDeveloping a robust app is painful

Developing a good UX app is painful

Thread, Executor, Handler, AsyncTask, Loader ...

RxJava can mitigate your pain

Retro�t 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")

Observable<Photo> getUserPhoto(@Path("id") int id);

http://misgod.github.io/Slide-FRP-Android/ 第 47 ⾴

Page 48: Functional Reactive Programming on Android

RxAndroid

Don't forget to unsubscribe to avoid memory leak!

Android speci�c bindings for RxJava.

Scheduler on main UI thread or a given Android Handler thread.

Reactive components for common Android use cases and UI widgets

·

https://github.com/ReactiveX/RxAndroid-

·

AndroidSchedulers

HandlerThreadScheduler

-

-

·

AndroidObservable

ViewObservable

-

-

http://misgod.github.io/Slide-FRP-Android/ 第 48 ⾴

Page 49: Functional Reactive Programming on Android

Thinking in Functional Reactive

http://misgod.github.io/Slide-FRP-Android/ 第 49 ⾴

Page 50: Functional Reactive Programming on Android

Case 1 - Say Hello to Callback Hell/* API */

void getFromServer(String key, Action1<String> callback);

void getFromDB(String key, Action1<String> callback);

/* Code */

btnClick.setOnClickListener(new View.OnClickListener() {

public void onClick(View view) {

getFromDB("myid", new Action1<String>() {

public void call(String s) {

getFromServer(s, new Action1<String>() {

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 ⾴

Page 51: Functional Reactive Programming on Android

Case 1 - Say Hello to Callback HellUsing 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 ⾴

Page 52: Functional Reactive Programming on Android

Case 1 - Say Goodbye to Callback HellUsing rx.Observable

/* API */

Observable<String> getFromServer(String key);

Observable<String> 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 ⾴

Page 53: Functional Reactive Programming on Android

Case 2 - All In One searchRequirements

A search engine includes google/yahoo/bing search results.1.

Should search di�erent engines in parallel2.

Retry 3 times when search fail3.

remove redundant url4.

Observable<SearchResult> g = googleSearch.search(keyword).retry(3);

Observable<SearchResult> b = bingSearch.search(keyword).retry(3);

Observable<SearchResult> 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 ⾴

Page 54: Functional Reactive Programming on Android

Case 3 - A simple EventBusPublishSubject<Object> 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 ⾴

Page 55: Functional Reactive Programming on Android

Case 4 - Input Suggestion

private Observable<String> getSuggestion(String prefix) { ... }

Observable<Observable<List<String>>> o =

ViewObservable.text(aEditText)

.map(event -> event.text.toString())

.filter(x -> x.length() > 1)

.observeOn(Schedulers.io())

.map(x -> getSuggestion(x).toList());

Observable.switchOnNext(o)

.observeOn(AndroidSchedulers.mainThread())

.subscribe(lst -> showSuggestion(lst));

http://misgod.github.io/Slide-FRP-Android/ 第 55 ⾴

Page 56: Functional Reactive Programming on Android

Conclusion

Functional Reactive makes async/state design straightforward.1.

RxJava is not just a library.2.

The most important is Functional Reactive Thinking.3.

Try It in your next project!4.

http://misgod.github.io/Slide-FRP-Android/ 第 56 ⾴

Page 57: Functional Reactive Programming on Android

http://misgod.github.io/Slide-FRP-Android/ 第 57 ⾴