Upload
mitchell-wong-ho
View
111
Download
2
Embed Size (px)
Citation preview
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
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