Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ReactiveX in Action

ReactiveX in Action

A talk about an API for asynchronous programming with Observable streams

Mitchell Wong Ho

January 26, 2016
Tweet

Transcript

  1. R e a c t i v e X A

    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
  2. A G E N D A • Introduction • Real

    World Example 1- Composing • Real World Example 2 - Combining Events • References • Q&RT
  3. I N T R O D U C T I

    O N • Observer-pattern for data- streams with operators. • Composable • Flexible • Asynchronous • Safe
  4. 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
  5. 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);
 }
  6. 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)
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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());
 }
 });
 }
  13. 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());
 }
 });
 }
  14. 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());
 }
 });
 }
  15. 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());
 }
  16. R E F E R E N C E S

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