rx in-action

20
ReactiveX A TALK ABOUT AN API FOR ASYNCHRONOUS PROGRAMMING WITH OBSERVABLE STREAMS

Upload: mitchell-wong-ho

Post on 14-Apr-2017

111 views

Category:

Software


2 download

TRANSCRIPT

R e a c t i v e XA TA L K A B O U T A N A P I F O R A S Y N C H R O N O U S P R O G R A M M I N G W I T H O B S E R VA B L E S T R E A M S

AGENDA

• Introduction

• Real World Example 1- Composing

• Real World Example 2 - Combining Events

• References

• Q&RT

I N T R O D U C T I O N

• Observer-pattern for data-streams with operators.

• Composable

• Flexible

• Asynchronous

• Safe

I N T R O D U C T I O N

I N T R O D U C T I O N

C O M P O S I N G O P E R AT I O N S

• Observer-pattern for data-streams with operators.

• Create operators

✦ Create/Interval/Range

• Transform operators

✦ Map/FlatMap/Window

• Filter operators

✦ Filter/Take/Debounce

• Combining operators

R E A L W O R L D E X A M P L E 1 - C O M P O S I N G

Use Case: Create a User account via a REST API

final public Observable<User> addUser(@NonNull final User user) { return pseudoEndPoint.addUser(user);}

R E A L W O R L D E X A M P L E 1 - C O M P O S I N G

nue = new NetworkUnavailableError(context.getString(R.string.network_unavailable));

private Observable<Boolean> checkNetworkStatus() { return Observable.<Boolean>create(subscriber -> { final NetworkInfo net = cm.getActiveNetworkInfo(); if (net == null || !net.isConnected()) { subscriber.onError(nue); } subscriber.onNext(true); subscriber.onCompleted(); }).subscribeOn(Schedulers.io()).observeOn(Schedulers.io());}

final public Observable<User> addUser(@NonNull final User user) { return checkNetworkStatus().flatMap( aBoolean -> { return pseudoEndPoint.addUser(user); } );}

Use Case: Create a User account via a REST API (must be online)

R E A L W O R L D E X A M P L E 1 - C O M P O S I N G

final public Observable<User> addUser(@NonNull final User user) { return pseudoEndPoint.addUser(user);}

nue = new NetworkUnavailableError(context.getString(R.string.network_unavailable));

private Observable<Boolean> checkNetworkStatus() { return Observable.<Boolean>create(subscriber -> { final NetworkInfo net = cm.getActiveNetworkInfo(); if (net == null || !net.isConnected()) { subscriber.onError(nue); } subscriber.onNext(true); subscriber.onCompleted(); }).subscribeOn(Schedulers.io()).observeOn(Schedulers.io());}

final public Observable<User> addUser(@NonNull final User user) { return checkNetworkStatus().flatMap( aBoolean -> { return pseudoEndPoint.addUser(user); } );}

nue = new NetworkUnavailableError(context.getString(R.string.network_unavailable));

public Observable<AuthToken> getAccessToken(@NonNull final String apiKey, @NonNull final String secretKey) { final String credentials = String.format("%s:%s", apiKey, secretKey); final String authString = String.format("Basic %s", Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP)); return endpoint.postApiAuthorisation(authString, "client_credentials") .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io());}

private Observable<Boolean> checkNetworkStatus() { … }

public Observable<User> addNewUser(@NonNull final User user) { final String headerAuthorisation = String.format("Bearer %s", authToken.accessToken); return checkNetworkStatus().flatMap(aBoolean -> { return endpoint.postNewUser(headerAuthorisation, user).onErrorResumeNext(throwable -> { if (throwable instanceof UnauthorizedError) { // refresh auth token return getAccessToken(keyAPi, keySecret).flatMap(authToken1 -> { synchronized (authToken) { authToken.merge(authToken1); return addNewUser(user); } }); } else { return Observable.error(throwable); } }); });}

Use Case: Create a User account via a REST API (must be online) using OAuth authentication

C O M B I N I N G O B S E R VA B L E S

• Observer-pattern for data-streams with operators.

• Combining operators

✦ Zip/Merge/CombineLatest

R E A L W O R L D E X A M P L E 2 - C O M B I N I N G

Zip() - Combine emission from multiple Observables into a single emission

R E A L W O R L D E X A M P L E 2 - C O M B I N I N G

Merge() - Combine multiple Observables into a single Observable

R E A L W O R L D E X A M P L E 2 - C O M B I N I N G

CombineLatest() - Combine latest item by each Observable via a function and emit items based on the result

R E A L W O R L D E X A M P L E 2 - C O M B I N I N G

Use Case: Receive HR metrics

private Observable<HrSession>createHrSessionListenerObservable() { return Observable.<HrSession>create(subscriber-> { final HrCallback callback=hrSession->{ subscriber.onNext(hrSession); // Check if we are done if(hrSession.getEvent()==HrEventType.HR_DONE){ subscriber.onCompleted(); } }; // Execute with our listener final Response response=WearableSDK.hrSessionListener(callback); if(response.hasError()){ subscriber.onError(new WearableError(response.getError())); }else{ Log.d(TAG,"createHrSessionListenerObservable {code=%d}",response.getCode()); } });}

R E A L W O R L D E X A M P L E 2 - C O M B I N I N G

Use Case: Receive HR metrics AND poll battery status

private Observable<BatteryCharge> pollBatteryChargeObservable() { return Observable.<Long>interval(1, TimeUnit.MINUTES).startWith(0L).flatMap(aLong1 -> getBatteryChargeObservable(false) ).subscribeOn(Schedulers.from(mExecutor));}

private Observable<HrSession>createHrSessionListenerObservable() { return Observable.<HrSession>create(subscriber-> { final HrCallback callback=hrSession->{ subscriber.onNext(hrSession); // Check if we are done if(hrSession.getEvent()==HrEventType.HR_DONE){ subscriber.onCompleted(); } }; // Execute with our listener final Response response=WearableSDK.hrSessionListener(callback); if(response.hasError()){ subscriber.onError(new WearableError(response.getError())); }else{ Log.d(TAG,"createHrSessionListenerObservable {code=%d}",response.getCode()); } });}

R E A L W O R L D E X A M P L E 2 - C O M B I N I N G

Use Case: Receive HR metrics AND poll battery AND poll memory status

private Observable<BatteryCharge> pollBatteryChargeObservable() { return Observable.<Long>interval(1, TimeUnit.MINUTES).startWith(0L).flatMap(aLong1 -> getBatteryChargeObservable(false) ).subscribeOn(Schedulers.from(mExecutor));}

private Observable<MemoryUsage> pollMemoryUsageObservable() { return Observable.<Long>interval(1, TimeUnit.MINUTES).startWith(0L).flatMap(aLong1 -> getMemoryUsageObservable(false) ).subscribeOn(Schedulers.from(mExecutor));}

private Observable<HrSession>createHrSessionListenerObservable() { return Observable.<HrSession>create(subscriber-> { final HrCallback callback=hrSession->{ subscriber.onNext(hrSession); // Check if we are done if(hrSession.getEvent()==HrEventType.HR_DONE){ subscriber.onCompleted(); } }; // Execute with our listener final Response response=WearableSDK.hrSessionListener(callback); if(response.hasError()){ subscriber.onError(new WearableError(response.getError())); }else{ Log.d(TAG,"createHrSessionListenerObservable {code=%d}",response.getCode()); } });}

R E A L W O R L D E X A M P L E 2 - C O M B I N I N G

Use Case: Receive HR metrics AND poll battery AND poll memory status

private Observable<BatteryCharge> pollBatteryChargeObservable() {…}

private Observable<MemoryUsage> pollMemoryUsageObservable() {…}

private Observable<HrSession>createHrSessionListenerObservable() {…}

public Observable<HRSessionEvent> getHrSessionListenerObservable() { /** * NB: Notice that HR Session Listener Observable is timestamped. This is * so we can determine if the device has stopped emitting events while * the Interval-Observable continues emitting. */ return Observable.<Timestamped<HrSession>, BatteryCharge, MemoryUsage, Long, HRSessionEvent>combineLatest( createHrSessionListenerObservable().timestamp(), pollBatteryChargeObservable(), pollMemoryUsageObservable(), getTickObservable(), (hrSessionTimestamped, batteryCharge, memoryUsage, aLong) -> { return HRSessionEvent.create(hrSessionTimestamped.getValue(), aLong.longValue(), hrSessionTimestamped.getTimestampMillis(), batteryCharge.getCharge(), memoryUsage.getMemoryUsage()); }) .timeout(5, TimeUnit.SECONDS) .subscribeOn(Schedulers.from(mExecutor)) .observeOn(AndroidSchedulers.mainThread());}

R E F E R E N C E S

• ReactiveX - http://reactivex.io • RxMarbles - http://rxmarbles.com

Q & R T

T h a n k Yo u