reactive programming on android

102
Reactive programming on Android Tomáš Kypta

Upload: tomas-kypta

Post on 16-Jan-2017

157 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: Reactive programming on Android

Reactive programming on AndroidTomáš Kypta

Page 2: Reactive programming on Android

What’s RxJava

Page 3: Reactive programming on Android

What’s RxJava

▪ combination of

– observer pattern

– iterator pattern

– functional programming

▪ composable data flow

▪ push concept

Page 4: Reactive programming on Android

Key Parts

▪ Observable

▪ Observer, Subscriber

▪ Subject

Page 5: Reactive programming on Android

Key Methods

▪ onNext(T)

▪ onCompleted()

▪ onError(Throwable)

Page 6: Reactive programming on Android

Key Methods

▪ subscribers can be replaced with Action parameters

someObservable.subscribe( onNextAction, onErrorAction, onCompleteAction);

Page 7: Reactive programming on Android

Key Methods

▪ we often ignore onError() and onComplete()

▪ risk of crashes when error occurs

someObservable.subscribe( onNextAction);

Page 8: Reactive programming on Android

What is RxJava good for?

▪ Async processing

– AsyncTask

– AsyncTaskLoader

– …

Page 9: Reactive programming on Android

What is RxJava good for?

▪ Async composition

– nested API calls

– AsyncTask callback hell

– There’s no way to do it right!

Page 10: Reactive programming on Android

What is RxJava good for?

▪ Testability

Page 11: Reactive programming on Android

Pros & Cons

▪ powerful tool

▪ conceptually difficult

– there are some tricky parts

Page 12: Reactive programming on Android

RxJava & app architecture

▪ suitable both for MVP and MVVM

Page 13: Reactive programming on Android

Example

Observable.just("Hello, world!") .subscribe(new Action1<String>() { @Override public void call(String s) { Timber.d(s); } });

Page 14: Reactive programming on Android

ExampleObservable.just("Hello, world!") .subscribe(new Subscriber<String>() { @Override public void onCompleted() {…}

@Override public void onError(Throwable e) {…}

@Override public void onNext(String s) { Timber.d(s); } });

Page 15: Reactive programming on Android

Retrolambda

▪ Enables Java 8 lambdas on Android

Page 16: Reactive programming on Android

Tip #1 - use Retrolambda

Observable.just("Hello, world!") .subscribe(s -> Timber.d(s));

Observable.just("Hello, world!") .subscribe(new Action1<String>() { @Override public void call(String s) { Timber.d(s); } });

Page 17: Reactive programming on Android

Observer vs. Subscriber

?

myObservable .subscribe(new Observer<String>() { @Override public void onCompleted() {}

@Override public void onError(Throwable e) {}

@Override public void onNext(String s) {} });

myObservable .subscribe(new Subscriber<String>() { @Override public void onCompleted() {}

@Override public void onError(Throwable e) {}

@Override public void onNext(String s) {} });

Page 18: Reactive programming on Android

Observer vs. Subscriber

▪ simpler unsubscribe() with Subscriber

myObservable .subscribe(new Subscriber<String>() { @Override public void onCompleted() { unsubscribe(); }

@Override public void onError(Throwable e) {}

@Override public void onNext(String s) {} });

Page 19: Reactive programming on Android

Operators

Page 20: Reactive programming on Android

Operators

▪ creation

▪ filtering

▪ combining

▪ transforming

▪ …

Page 21: Reactive programming on Android

Understanding operators

▪ marble diagrams

▪ RxMarbles

– rxmarbles.com

– Android app

Page 22: Reactive programming on Android

Observable Creation

▪ create()

▪ from()

▪ just()

Page 23: Reactive programming on Android

Observable Creation

▪ corner cases

▪ empty()

▪ never()

▪ error()

Page 24: Reactive programming on Android

Filtering

▪ filter()

▪ takeLast()

▪ take()

Page 25: Reactive programming on Android

Filtering

▪ first(), take(int)

▪ skip()

▪ distinct()

▪ …

Page 26: Reactive programming on Android

Combining

▪ merge()

▪ zip()

Page 27: Reactive programming on Android

Transforming

▪ map()

▪ flatMap()

▪ concatMap()

Page 28: Reactive programming on Android

map vs. flatMap vs. concatMap▪ map

– A -> B

– one in, one out

▪ flatMap

– A -> Observable<B>

– map + flatten

▪ concatMap

– ordered flatMap

Page 29: Reactive programming on Android

Aggregate

▪ concat()

▪ reduce

Page 30: Reactive programming on Android

Operators

▪ and there’s much more …

Page 31: Reactive programming on Android

Example

Observable.from(myUrls)

Page 32: Reactive programming on Android

Example

Observable.from(myUrls) .filter(url -> url.endsWith(".cz"))

Page 33: Reactive programming on Android

Example

Observable.from(myUrls) .filter(url -> url.endsWith(".cz")) .flatMap(url -> Observable.just(getHttpStatus(url)))

Page 34: Reactive programming on Android

Example

Observable.from(myUrls) .filter(url -> url.endsWith(".cz")) .flatMap(url -> Observable.just(getHttpStatus(url))) .take(5)

Page 35: Reactive programming on Android

Example

Observable.from(myUrls) .filter(url -> url.endsWith(".cz")) .flatMap(url -> Observable.just(getHttpStatus(url))) .take(5) .subscribe(s -> Timber.i(String.valueOf(s)));

Page 36: Reactive programming on Android

Threading

Page 37: Reactive programming on Android

Threading

▪ subscribeOn(Scheduler)

▪ subscribes to Observable on the Scheduler

▪ observeOn(Scheduler)

▪ Observable emits on the Scheduler

Page 38: Reactive programming on Android

Schedulers

Page 39: Reactive programming on Android

Schedulers

▪ computation()

▪ io()

▪ newThread()

▪ from(Executor)

Page 40: Reactive programming on Android

computation() vs. io()

▪ io()

– unbounded thread pool

– I/O operations

▪ computation()

– bounded thread pool

– CPU intensive computational work

Page 41: Reactive programming on Android

AndroidSchedulers

▪ mainThread()

▪ from(Looper)

Page 42: Reactive programming on Android

subscribeOn()

▪ subscribeOn()

– multiple calls useless

– only the first call works!

– for all operators

Page 43: Reactive programming on Android

observeOn()

▪ can be called multiple times

Page 44: Reactive programming on Android

Threading

▪ operators have default Schedulers

▪ check Javadoc for it

Page 45: Reactive programming on Android

Threading

▪ range()

– no preference, uses current thread

▪ interval()

– computation() thread

Page 46: Reactive programming on Android

Threading

▪ just()

– current thread

▪ delay(long, TimeUnit)

– computation() thread

Page 47: Reactive programming on Android

Observable methods

▪ extra actions

▪ doOnNext()

▪ doOnError()

▪ doOnSubscribe()

▪ doOnUnsubscribe()

▪ …

Page 48: Reactive programming on Android

Async composition

apiEndpoint.login()

Page 49: Reactive programming on Android

Async composition

apiEndpoint.login() .doOnNext(accessToken -> storeCredentials(accessToken))

Page 50: Reactive programming on Android

Async composition

apiEndpoint.login() .doOnNext(accessToken -> storeCredentials(accessToken)) .flatMap(accessToken -> serviceEndpoint.getUser())

Page 51: Reactive programming on Android

Async composition

apiEndpoint.login() .doOnNext(accessToken -> storeCredentials(accessToken)) .flatMap(accessToken -> serviceEndpoint.getUser()) .flatMap(user -> serviceEndpoint.getUserContact(user.getId()))

Page 52: Reactive programming on Android

Subscription

Page 53: Reactive programming on Android

Subscription

Subscription s = mAppInfoProvider.getAppsObservable() .subscribe( appInfo -> Timber.i(appInfo.getPackageName() );

Page 54: Reactive programming on Android

Subscription

Subscription s = mAppInfoProvider.getAppsObservable() .subscribe( appInfo -> Timber.i(appInfo.getPackageName() );

s.unsubscribe();

Page 55: Reactive programming on Android

Subscription

Subscription s = mAppInfoProvider.getAppsObservable() .subscribe( appInfo -> Timber.i(appInfo.getPackageName() );

s.unsubscribe();Timber.i("unsubscribed: " + s.isUnsubscribed());

Page 56: Reactive programming on Android

CompositeSubscription

CompositeSubscription compositeSubscription = new CompositeSubscription();

compositeSubscription.add(subscription);

Page 57: Reactive programming on Android

CompositeSubscription

CompositeSubscription compositeSubscription = new CompositeSubscription();

compositeSubscription.add(subscription);

compositeSubscription.unsubscribe();

Page 58: Reactive programming on Android

CompositeSubscription

CompositeSubscription compositeSubscription = new CompositeSubscription();

compositeSubscription.add(subscription);

compositeSubscription.unsubscribe();

compositeSubscription.clear();

Page 59: Reactive programming on Android

Bridging non-Rx APIs

Page 60: Reactive programming on Android

Bridging non-Rx APIs

▪ just()

private Object getData() {...}

public Observable<Object> getObservable() { return Observable.just(getData());}

Page 61: Reactive programming on Android

Tip #2 - defer()

▪ use defer() to avoid immediate execution

private Object getData() {...}

public Observable<Object> getObservable() { return Observable.defer( () -> Observable.just(getData()) );}

Page 62: Reactive programming on Android

Subjects

Page 63: Reactive programming on Android

Subjects

▪ Observable & Observer

▪ bridge between non-Rx API

▪ stateful

– terminal state

▪ don’t pass data after onComplete()/onError()

Page 64: Reactive programming on Android

Subjects

▪ cannot be reused

– always create a new instance when subscribing to an Observable

Page 65: Reactive programming on Android

Subjects

▪ AsyncSubject

▪ BehaviorSubject

▪ ReplaySubject

▪ PublishSubject

▪ SerializedSubject

Page 66: Reactive programming on Android

Subjects

Subject subject = …subject.subscribe(subscriber);subject.onNext(A);subject.onNext(B);

Page 67: Reactive programming on Android

AsyncSubject

▪ last item, after Observable completes

Page 68: Reactive programming on Android

BehaviorSubject

▪ emits most recent and all subsequent items

Page 69: Reactive programming on Android

PublishSubject

▪ emits only subsequent items

Page 70: Reactive programming on Android

ReplaySubject

▪ emit all the items

Page 71: Reactive programming on Android

RxRelay

Page 72: Reactive programming on Android

RxRelay

▪ https://github.com/JakeWharton/RxRelay

▪ Relay = Observable & Action1

▪ call()

▪ Relay = Subject - onComplete() - onError()

Page 73: Reactive programming on Android

RxRelay

▪ Subject

▪ stateful

▪ Relay

▪ stateless

Page 74: Reactive programming on Android

RxRelay

Relay relay = …relay.subscribe(observer);relay.call(A);relay.call(B);

Page 75: Reactive programming on Android

RxRelay

▪ BehaviorRelay

▪ PublishRelay

▪ ReplayRelay

▪ SerializedRelay

Page 76: Reactive programming on Android

Android Lifecycle

▪ problems

▪ continuing Subscription during configuration change

▪ memory leaks

Page 77: Reactive programming on Android

Android Lifecycle

▪ continuing Subscription during configuration change

▪ cache()

▪ replay()

Page 78: Reactive programming on Android

Android Lifecycle

▪ memory leaks

▪ bind to Activity/Fragment lifecycle

▪ RxLifecycle

Page 79: Reactive programming on Android

RxLifecycle

Page 80: Reactive programming on Android

RxLifecycle

▪ auto unsubscribe based on Activity/Fragment lifecyclemyObservable .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) .subscribe();

myObservable .compose(RxLifecycle.bindActivity(lifecycle)) .subscribe();

Page 81: Reactive programming on Android

RxLifecycle

▪ obtain ActivityEvent or FragmentEvent by:

A. rxlifecycle-components + subclass RxActivity, RxFragment

B. Navi + rxlifecycle-navi

C. Write it yourself

Page 82: Reactive programming on Android

RxLifecycle

public class MyActivity extends RxActivity { @Override public void onResume() { super.onResume(); myObservable .compose(bindToLifecycle()) .subscribe(); }}

Page 83: Reactive programming on Android

RxLifecyclepublic class MyActivity extends NaviActivity { private final ActivityLifecycleProvider provider = NaviLifecycle.createActivityLifecycleProvider(this);

@Override public void onResume() { super.onResume(); myObservable .compose(provider.bindToLifecycle()) .subscribe(…); }}

Page 84: Reactive programming on Android

Navi

naviComponent.addListener(Event.CREATE, new Listener<Bundle>() { @Override public void call(Bundle bundle) { setContentView(R.layout.main); } });

Page 85: Reactive programming on Android

RxNavi

RxNavi.observe(naviComponent, Event.CREATE) .subscribe(bundle -> setContentView(R.layout.main));

Page 86: Reactive programming on Android

RxLifecyclepublic class MainActivityFragment extends Fragment {

BehaviorSubject<FragmentEvent> mLifecycleSubject = BehaviorSubject.create();

Page 87: Reactive programming on Android

RxLifecyclepublic class MainActivityFragment extends Fragment {

BehaviorSubject<FragmentEvent> mLifecycleSubject = BehaviorSubject.create();

@Override public void onResume() { super.onResume(); RxView.clicks(vBtn) .compose(RxLifecycle.bindUntilEvent(mLifecycleSubject, FragmentEvent.PAUSE)) .doOnUnsubscribe(() -> Timber.i("onUnsubscribe")) .subscribe(…); }

}

Page 88: Reactive programming on Android

RxLifecyclepublic class MainActivityFragment extends Fragment {

BehaviorSubject<FragmentEvent> mLifecycleSubject = BehaviorSubject.create();

@Override public void onResume() { super.onResume(); RxView.clicks(vBtn) .compose(RxLifecycle.bindUntilEvent(mLifecycleSubject, FragmentEvent.PAUSE)) .doOnUnsubscribe(() -> Timber.i("onUnsubscribe")) .subscribe(…); }

@Override public void onPause() { super.onPause(); Timber.i("onPause"); mLifecycleSubject.onNext(FragmentEvent.PAUSE); }}

Page 89: Reactive programming on Android

RxBinding

Page 90: Reactive programming on Android

RxBinding

▪ binding for UI widgets

Page 91: Reactive programming on Android

RxBinding

RxView.clicks(vBtnSearch) .subscribe( v -> { Intent intent = new Intent(getActivity(), SearchActivity.class); startActivity(intent); } );

Page 92: Reactive programming on Android

RxBinding

RxTextView.textChanges(vEtSearch) .subscribe( response -> Timber.i("Count: " + response.totalCount()) );

Page 93: Reactive programming on Android

RxBinding

RxTextView.textChanges(vEtSearch) .debounce(2, TimeUnit.SECONDS) .subscribe( response -> Timber.i("Count: " + response.totalCount()) );

Page 94: Reactive programming on Android

RxBinding

RxTextView.textChanges(vEtSearch) .debounce(2, TimeUnit.SECONDS) .observeOn(Schedulers.io()) .flatMap(s -> mApiService.search(s.toString())) .subscribe( response -> Timber.i("Count: " + response.totalCount()) );

Page 95: Reactive programming on Android

RxBinding

▪ compile ‘com.jakewharton.rxbinding:rxbinding:0.4.0'

▪ compile ‘com.jakewharton.rxbinding:rxbinding-support-v4:0.4.0'

▪ compile ‘com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.4.0'

▪ compile ‘com.jakewharton.rxbinding:rxbinding-design:0.4.0'

▪ compile ‘com.jakewharton.rxbinding:rxbinding-recyclerview-v7:0.4.0'

▪ compile 'com.jakewharton.rxbinding:rxbinding-leanback-v17:0.4.0'

Page 96: Reactive programming on Android

Retrofit

Page 97: Reactive programming on Android

Retrofit

▪ sync or async API

@GET("group/{id}/users")Call<List<User>> groupList(@Path("id") int groupId);

Page 98: Reactive programming on Android

Retrofit

▪ reactive API

@GET("group/{id}/users")Observable<List<User>> groupList(@Path("id") int groupId);

Page 99: Reactive programming on Android

Retrofit

– onNext() with Response, then onComplete()

– onError() in case of error

@GET("/data")Observable<Response> getData( @Body DataRequest dataRequest);

Page 100: Reactive programming on Android

Retrofit

RxTextView.textChanges(vEtSearch) .debounce(2, TimeUnit.SECONDS) .observeOn(Schedulers.io()) .flatMap(s -> mApiService.search(s.toString())) .subscribe( response -> Timber.i("Count: " + response.totalCount()) );

Page 101: Reactive programming on Android

SQLBrite

Page 102: Reactive programming on Android

THE END