Reactive Programming
RxJava for android
Richard Radics
Lead Android Developer
We are Supercharge
We experiment, we move fast,
we make it happen
At Supercharge we build high-impact mobile products making life easier for millions of users. Creating
stunning experiences can only happen if you stretch yourself. To supercharge means to go that extra mile.
Telekom RO
The official self-care application of the Deutsche Telekom was completed within 14 weeks on iOS and Android. The application amassed nearly 1M downloads to
date in the first launch country, Romania. The core functionality of the app became the model for DT’s European-wide self-care application and is expected to be
rolled out in 8-10 countries in 2016. Supercharge currently maintains the core codebase and 3 countries.
Jenius
Indonesia’s fastest growing financial institute’s new app is an exciting example of modern mobile banking solutions. BTPN has over 100 million customer in the South East Asian region:
their new app offers unique User Experience for all of them through its innovative functionality. Just to name a few interesting features: bill splitting enables coworkers to easily divide
their lunch expenses, with the Cashtag function users can easily transfer money to “#someone” with the use of tagging. We are especially proud that our extremely effectively
workflows and processes made it possible to reach the UAT phase of an app consisting of over 170 screens within 3 months of development (on two mobile platforms simultaneously).
The application has been developed in cooperation with Misys.
Let’s start…
Supercharge 6
Reactive Programming
Supercharge 7
Erik Meijer – Rx .Net Ben Christensen - RxJava
ReactiveX
•  Data Flow
•  Observer Pattern
•  Push vs Pull
Supercharge 8
Creating Observables
From
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
public Observable<Integer> fromExample() {!
return Observable.from(testIntData);!
}!
!
!
Converts an iterable into an observable that emits all items
in the iterable and calls onComplete. The resulting observable
works synchronously.
Supercharge 12
From
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
public Observable<Integer> fromExample() {!
return Observable.from(testIntData);!
}!
!
!
Converts an iterable into an observable that emits all items
in the iterable and calls onComplete. The resulting observable
works synchronously.
Supercharge 13
Just
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
public Observable<Integer[]> justExample() {!
return Observable.just(testIntData);!
}!
Emit the object in onNext and calls onComplete.
Does not try to iterate the object.
Supercharge 14
Just
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
public Observable<Integer[]> justExample() {!
return Observable.just(testIntData);!
}!
Emit the object in onNext and calls onComplete.
Does not try to iterate the object.
Supercharge 15
Create
Observable<Integer> getDataAsync(int i) {!
return getDataSync(i).subscribeOn(Schedulers.io());!
}!
Observable<Integer> getDataSync(int i) {!
return Observable.create(subscriber -> {!
try { !
Thread.sleep(rand(100, 500)); !
subscriber.onNext(i);!
subscriber.onCompleted();!
}catch (Exception e){!
subscriber.onError(e);!
}!
});!
}!
Supercharge 16
Create
Observable<Integer> getDataAsync(int i) {!
return getDataSync(i).subscribeOn(Schedulers.io());!
}!
Observable<Integer> getDataSync(int i) {!
return Observable.create(subscriber -> {!
try { !
Thread.sleep(rand(100, 500)); !
subscriber.onNext(i);!
subscriber.onCompleted();!
}catch (Exception e){!
subscriber.onError(e);!
}!
});!
}
Supercharge 17
Operators
Filter
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.filter(integer -> integer % 2 == 0)!
.subscribe(System.out::println);!
Supercharge 19
Filter
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.filter(integer -> integer % 2 == 0)!
.subscribe(System.out::println);!
// 2
// 4
Supercharge 20
Take first N values
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.take(2)!
.subscribe(System.out::println);!
!
!
Supercharge 21
Take first N values
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.take(2)!
.subscribe(System.out::println);!
// 1
// 2
Supercharge 22
First
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.first()!
.subscribe(System.out::println);!
Supercharge 23
First
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.first()!
.subscribe(System.out::println);!
// 1
Supercharge 24
Last
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.last()!
.subscribe(System.out::println); !
Supercharge 25
Last
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.last()!
.subscribe(System.out::println); !
// 5
Supercharge 26
Group by
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.groupBy(integer -> integer % 2 == 0)!
.subscribe(grouped -> {!
grouped.toList().subscribe(groupedLists ->!
log(grouped.getKey() + " " + groupedLists)!
});!
});!
Supercharge 27
Group by
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.groupBy(integer -> integer % 2 == 0)!
.subscribe(grouped -> {!
grouped.toList().subscribe(groupedLists ->!
log(grouped.getKey() + " " + groupedLists)!
});!
});!
Supercharge 28
Group by
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.groupBy(integer -> integer % 2 == 0)!
.subscribe(grouped -> {!
grouped.toList().subscribe(groupedLists ->!
log(grouped.getKey() + " " + groupedLists) !
});!
});!
//false
//true
Supercharge 29
Group by
Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};!
Observable!
.from(testIntData)!
.groupBy(integer -> integer % 2 == 0)!
.subscribe(grouped -> {!
grouped.toList().subscribe(groupedLists ->!
log(grouped.getKey() + " " + groupedLists) !
});!
});!
//false 1, 3, 5
//true 2, 4
Supercharge 30
Distinct
String[] testDistinctData = new String[]{"a", "b", "a",
“c", "c", "d"};!
Observable!
.from(testDistinctData)!
.distinct()!
.subscribe(s -> log(s));!
Supercharge 31
Distinct
String[] testDistinctData = new String[]{"a", "b", "a",
“c", "c", "d"};!
Observable!
.from(testDistinctData)!
.distinct()!
.subscribe(s -> log(s));!
//a, b, c, d
Supercharge 32
Map
Observable.just("RxPresentation")!
.map(encoded -> Base64.encode(encoded.getBytes())
.subscribe(TestUtil::log);!
Supercharge 33
Map
Observable.just("RxPresentation")!
.map(encoded -> Base64.encode(encoded.getBytes())
.subscribe(TestUtil::log);!
//UnhQcmVzZW50YXRpb24=
Supercharge 34
Map
Observable.just("RxPresentation")!
.map(encoded -> Base64.encode(encoded.getBytes())
.map(s -> new String(Base64.decode(s))!
.subscribe(TestUtil::log);!
//RxPresentation
Supercharge 35
FlatMap
Observable.range(1, 6)!
.flatMap(integer -> getDataAsync(integer))!
.subscribe(TestUtil::log);!
Supercharge 36
FlatMap
Observable.range(1, 6)!
.flatMap(integer -> getDataAsync(integer))!
.subscribe(TestUtil::log);!
// 1, 2, 3, 4, 5, 6
Supercharge 37
FlatMap
Observable.range(1, 6)!
.flatMap(integer -> getDataAsync(integer))!
.subscribe(TestUtil::log);!
// 3, 5, 1, 2, 4, 6
Supercharge 38
Advanced Scenario
Advanced Scenario
Supercharge 40


Advanced Scenario
Supercharge 41
•  Imagine that you have a login screen.
Advanced Scenario
Supercharge 42
•  Imagine that you have a login screen.
•  Your task is to validate the input fields and if everything is good, you enable
the login button.
Advanced Scenario
Supercharge 43
•  Imagine that you have a login screen.
•  Your task is to validate the input fields and if everything is good, you enable
the login button.
•  After login, download all the data for the application.
Advanced Scenario
Supercharge 44
•  Imagine that you have a login screen.
•  Your task is to validate the input fields and if everything is good, you enable
the login button.
•  After login, download all the data for the application.
•  For example: the user has services and bills. You can get it from different
sources.
Advanced Scenario
Supercharge 45


Advanced Scenario
Supercharge 46


•  Validate the input fields.
!
Observable.combineLatest(!
RxTextView.textChangeEvents(mEmailView),!
RxTextView.textChangeEvents(mPasswordView),!
(emailChange, passwordChange) -> {!
boolean emailOK = emailChange.text().length() >= 3;!
boolean passOK = passwordChange.text().length() >= 3;!
!
return emailOK && passOK;!
})!
.compose(bindToLifecycle())!
.subscribe(isValid -> mSignIn.setEnabled(isValid));!
Advanced Scenario
Supercharge 47


•  RxBinding provides binding for android’s UI widgets.
!
Observable.combineLatest(!
RxTextView.textChangeEvents(mEmailView),!
RxTextView.textChangeEvents(mPasswordView),!
(emailChange, passwordChange) -> {!
boolean emailOK = emailChange.text().length() >= 3;!
boolean passOK = passwordChange.text().length() >= 3;!
!
return emailOK && passOK;!
})!
.compose(bindToLifecycle())!
.subscribe(isValid -> mSignIn.setEnabled(isValid));!
Advanced Scenario
Supercharge 48


•  Combine and evaluate the changes.
!
Observable.combineLatest(!
RxTextView.textChangeEvents(mEmailView),!
RxTextView.textChangeEvents(mPasswordView),!
(emailChange, passwordChange) -> {!
boolean emailOK = emailChange.text().length() >= 3;!
boolean passOK = passwordChange.text().length() >= 3;!
!
return emailOK && passOK;!
})!
.compose(bindToLifecycle())!
.subscribe(isValid -> mSignIn.setEnabled(isValid));!
Advanced Scenario
Supercharge 49


•  Use RxLifeCycle by Trello to properly handle subscriptions.
!
Observable.combineLatest(!
RxTextView.textChangeEvents(mEmailView),!
RxTextView.textChangeEvents(mPasswordView),!
(emailChange, passwordChange) -> {!
boolean emailOK = emailChange.text().length() >= 3;!
boolean passOK = passwordChange.text().length() >= 3;!
!
return emailOK && passOK;!
})!
.compose(bindToLifecycle())!
.subscribe(isValid -> mSignIn.setEnabled(isValid));!
Advanced Scenario
Supercharge 50


•  Enable/Disable Sign in button
!
Observable.combineLatest(!
RxTextView.textChangeEvents(mEmailView),!
RxTextView.textChangeEvents(mPasswordView),!
(emailChange, passwordChange) -> {!
boolean emailOK = emailChange.text().length() >= 3;!
boolean passOK = passwordChange.text().length() >= 3;!
!
return emailOK && passOK;!
})!
.compose(bindToLifecycle())!
.subscribe(isValid -> mSignIn.setEnabled(isValid));!
Advanced Scenario
Supercharge 51
•  Process services first.
Observable<Services> saveServices = apiManager.services()!
.compose(rxUtils.applySchedulers())!
.map(serviceResponse -> mapServices(serviceResponse))!
.doOnNext(services -> saveServices(services));!


Advanced Scenario
Supercharge 52
•  Download data with Retrofit
Observable<Services> saveServices = apiManager.services()!
.compose(rxUtils.applySchedulers())!
.map(serviceResponse -> mapServices(serviceResponse))!
.doOnNext(services -> saveServices(services));!


!
@GET("/services")!
Observable<ServiceResponse> services();!
Advanced Scenario
Supercharge 53
•  Apply schedulers
Observable<Services> saveServices = apiManager.services()!
.compose(rxUtils.applySchedulers())!
.map(serviceResponse -> mapServices(serviceResponse))!
.doOnNext(services -> saveServices(services));!


public <T> Observable.Transformer<T, T> applyDefaultSchedulers() {!
return obs-> obs.subscribeOn(Schedulers.io()) !
.observeOn(AndroidSchedulers.mainThread());!
}!
}!
Advanced Scenario
Supercharge 54
•  Apply schedulers
Observable<Services> saveServices = apiManager.services()!
.compose(rxUtils.applySchedulers())!
.map(serviceResponse -> mapServices(serviceResponse))!
.doOnNext(services -> saveServices(services));!


public <T> Observable.Transformer<T, T> applyDefaultSchedulers() {!
return obs-> obs.subscribeOn(Schedulers.io()) !
.observeOn(AndroidSchedulers.mainThread());!
}!
}!
Advanced Scenario
Supercharge 55
•  Apply schedulers
Observable<Services> saveServices = apiManager.services()!
.compose(rxUtils.applySchedulers())!
.map(serviceResponse -> mapServices(serviceResponse))!
.doOnNext(services -> saveServices(services));!


public <T> Observable.Transformer<T, T> applyDefaultSchedulers() {!
return obs-> obs.subscribeOn(Schedulers.io()) !
.observeOn(AndroidSchedulers.mainThread());!
}!
}!
Advanced Scenario
Supercharge 56
•  Map response to domain model
Observable<Services> saveServices = apiManager.services()!
.compose(rxUtils.applySchedulers())!
.map(serviceResponse -> mapServices(serviceResponse))!
.doOnNext(services -> saveServices(services));!


Transforms the items emitted by an Observable applying a function to each
item.
Advanced Scenario
Supercharge 57
•  Save data to database
Observable<Services> saveServices = apiManager.services()!
.compose(rxUtils.applySchedulers())!
.map(serviceResponse -> mapServices(serviceResponse))!
.doOnNext(services -> saveServices(services));!


Advanced Scenario
Supercharge 58
•  Do things parallel
Observable<Services> saveServices = apiManager.services()!
.compose(rxUtils.applySchedulers())!
.map(serviceResponse -> mapServices(serviceResponse))!
.doOnNext(services -> saveServices(services));!


Observable<Bills> saveBills = apiManager.bills()!
.compose(rxUtils.applySchedulers())!
.map(billResponse -> mapBills(billResponse))!
.doOnNext(bills -> saveBills(bills));!
Advanced Scenario
Supercharge 59
•  Do things parallel
Observable.zip(saveServices, saveBills, !
(s, b) -> new LoadingResult(s, b))!
.compose(rxComposer.applySchedulers())!
.subscribe(loadingResult -> log(loadingResult));!
Advanced Scenario
Supercharge 60
•  Do things parallel
Observable.zip(saveServices, saveBills, !
(s, b) -> new LoadingResult(s, b))!
.compose(rxComposer.applySchedulers())!
.subscribe(loadingResult -> log(loadingResult));!
static class LoadingResult{!
public LoadingResult(Services service, Bills bill) {…}!
}!
Testing
•  RxJava asynchronus by nature
Supercharge 61
Testing
•  RxJava asynchronus by nature
•  At first sight a bit complicated to test
Supercharge 62
Testing
•  RxJava asynchronus by nature
•  At first sight a bit complicated to test
•  Luckily RxJava and RxAndroid come with a couple of tools
Supercharge 63
Testing
•  What to test?
Supercharge 64
Testing
•  What to test?
–  Observables: composition of the various operators
Supercharge 65
Testing
•  What to test?
–  Observables: composition of the various operators
–  How the rest of app behaves while triggered by a subscription
Supercharge 66
Questions?
Thanks for your attention!
Contact us!
Richard Radics
Supercharge
Lead Android Developer
richard.radics@supercharge.io // www.supercharge.io
Functional Reactive Programming (RxJava) on Android

Functional Reactive Programming (RxJava) on Android

  • 1.
    Reactive Programming RxJava forandroid Richard Radics Lead Android Developer
  • 2.
  • 3.
    We experiment, wemove fast, we make it happen At Supercharge we build high-impact mobile products making life easier for millions of users. Creating stunning experiences can only happen if you stretch yourself. To supercharge means to go that extra mile.
  • 4.
    Telekom RO The officialself-care application of the Deutsche Telekom was completed within 14 weeks on iOS and Android. The application amassed nearly 1M downloads to date in the first launch country, Romania. The core functionality of the app became the model for DT’s European-wide self-care application and is expected to be rolled out in 8-10 countries in 2016. Supercharge currently maintains the core codebase and 3 countries.
  • 5.
    Jenius Indonesia’s fastest growingfinancial institute’s new app is an exciting example of modern mobile banking solutions. BTPN has over 100 million customer in the South East Asian region: their new app offers unique User Experience for all of them through its innovative functionality. Just to name a few interesting features: bill splitting enables coworkers to easily divide their lunch expenses, with the Cashtag function users can easily transfer money to “#someone” with the use of tagging. We are especially proud that our extremely effectively workflows and processes made it possible to reach the UAT phase of an app consisting of over 170 screens within 3 months of development (on two mobile platforms simultaneously). The application has been developed in cooperation with Misys.
  • 6.
  • 7.
    Reactive Programming Supercharge 7 ErikMeijer – Rx .Net Ben Christensen - RxJava
  • 8.
    ReactiveX •  Data Flow • Observer Pattern •  Push vs Pull Supercharge 8
  • 11.
  • 12.
    From Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! public Observable<Integer> fromExample() {! return Observable.from(testIntData);! }! ! ! Converts an iterable into an observable that emits all items in the iterable and calls onComplete. The resulting observable works synchronously. Supercharge 12
  • 13.
    From Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! public Observable<Integer> fromExample() {! return Observable.from(testIntData);! }! ! ! Converts an iterable into an observable that emits all items in the iterable and calls onComplete. The resulting observable works synchronously. Supercharge 13
  • 14.
    Just Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! public Observable<Integer[]> justExample() {! return Observable.just(testIntData);! }! Emit the object in onNext and calls onComplete. Does not try to iterate the object. Supercharge 14
  • 15.
    Just Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! public Observable<Integer[]> justExample() {! return Observable.just(testIntData);! }! Emit the object in onNext and calls onComplete. Does not try to iterate the object. Supercharge 15
  • 16.
    Create Observable<Integer> getDataAsync(int i){! return getDataSync(i).subscribeOn(Schedulers.io());! }! Observable<Integer> getDataSync(int i) {! return Observable.create(subscriber -> {! try { ! Thread.sleep(rand(100, 500)); ! subscriber.onNext(i);! subscriber.onCompleted();! }catch (Exception e){! subscriber.onError(e);! }! });! }! Supercharge 16
  • 17.
    Create Observable<Integer> getDataAsync(int i){! return getDataSync(i).subscribeOn(Schedulers.io());! }! Observable<Integer> getDataSync(int i) {! return Observable.create(subscriber -> {! try { ! Thread.sleep(rand(100, 500)); ! subscriber.onNext(i);! subscriber.onCompleted();! }catch (Exception e){! subscriber.onError(e);! }! });! } Supercharge 17
  • 18.
  • 19.
    Filter Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .filter(integer -> integer % 2 == 0)! .subscribe(System.out::println);! Supercharge 19
  • 20.
    Filter Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .filter(integer -> integer % 2 == 0)! .subscribe(System.out::println);! // 2 // 4 Supercharge 20
  • 21.
    Take first Nvalues Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .take(2)! .subscribe(System.out::println);! ! ! Supercharge 21
  • 22.
    Take first Nvalues Integer[] testIntData = new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .take(2)! .subscribe(System.out::println);! // 1 // 2 Supercharge 22
  • 23.
    First Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .first()! .subscribe(System.out::println);! Supercharge 23
  • 24.
    First Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .first()! .subscribe(System.out::println);! // 1 Supercharge 24
  • 25.
    Last Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .last()! .subscribe(System.out::println); ! Supercharge 25
  • 26.
    Last Integer[] testIntData =new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .last()! .subscribe(System.out::println); ! // 5 Supercharge 26
  • 27.
    Group by Integer[] testIntData= new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .groupBy(integer -> integer % 2 == 0)! .subscribe(grouped -> {! grouped.toList().subscribe(groupedLists ->! log(grouped.getKey() + " " + groupedLists)! });! });! Supercharge 27
  • 28.
    Group by Integer[] testIntData= new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .groupBy(integer -> integer % 2 == 0)! .subscribe(grouped -> {! grouped.toList().subscribe(groupedLists ->! log(grouped.getKey() + " " + groupedLists)! });! });! Supercharge 28
  • 29.
    Group by Integer[] testIntData= new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .groupBy(integer -> integer % 2 == 0)! .subscribe(grouped -> {! grouped.toList().subscribe(groupedLists ->! log(grouped.getKey() + " " + groupedLists) ! });! });! //false //true Supercharge 29
  • 30.
    Group by Integer[] testIntData= new Integer[]{1, 2, 3, 4, 5};! Observable! .from(testIntData)! .groupBy(integer -> integer % 2 == 0)! .subscribe(grouped -> {! grouped.toList().subscribe(groupedLists ->! log(grouped.getKey() + " " + groupedLists) ! });! });! //false 1, 3, 5 //true 2, 4 Supercharge 30
  • 31.
    Distinct String[] testDistinctData =new String[]{"a", "b", "a", “c", "c", "d"};! Observable! .from(testDistinctData)! .distinct()! .subscribe(s -> log(s));! Supercharge 31
  • 32.
    Distinct String[] testDistinctData =new String[]{"a", "b", "a", “c", "c", "d"};! Observable! .from(testDistinctData)! .distinct()! .subscribe(s -> log(s));! //a, b, c, d Supercharge 32
  • 33.
  • 34.
  • 35.
    Map Observable.just("RxPresentation")! .map(encoded -> Base64.encode(encoded.getBytes()) .map(s-> new String(Base64.decode(s))! .subscribe(TestUtil::log);! //RxPresentation Supercharge 35
  • 36.
    FlatMap Observable.range(1, 6)! .flatMap(integer ->getDataAsync(integer))! .subscribe(TestUtil::log);! Supercharge 36
  • 37.
    FlatMap Observable.range(1, 6)! .flatMap(integer ->getDataAsync(integer))! .subscribe(TestUtil::log);! // 1, 2, 3, 4, 5, 6 Supercharge 37
  • 38.
    FlatMap Observable.range(1, 6)! .flatMap(integer ->getDataAsync(integer))! .subscribe(TestUtil::log);! // 3, 5, 1, 2, 4, 6 Supercharge 38
  • 39.
  • 40.
  • 41.
    Advanced Scenario Supercharge 41 • Imagine that you have a login screen.
  • 42.
    Advanced Scenario Supercharge 42 • Imagine that you have a login screen. •  Your task is to validate the input fields and if everything is good, you enable the login button.
  • 43.
    Advanced Scenario Supercharge 43 • Imagine that you have a login screen. •  Your task is to validate the input fields and if everything is good, you enable the login button. •  After login, download all the data for the application.
  • 44.
    Advanced Scenario Supercharge 44 • Imagine that you have a login screen. •  Your task is to validate the input fields and if everything is good, you enable the login button. •  After login, download all the data for the application. •  For example: the user has services and bills. You can get it from different sources.
  • 45.
  • 46.
    Advanced Scenario Supercharge 46 
 • Validate the input fields. ! Observable.combineLatest(! RxTextView.textChangeEvents(mEmailView),! RxTextView.textChangeEvents(mPasswordView),! (emailChange, passwordChange) -> {! boolean emailOK = emailChange.text().length() >= 3;! boolean passOK = passwordChange.text().length() >= 3;! ! return emailOK && passOK;! })! .compose(bindToLifecycle())! .subscribe(isValid -> mSignIn.setEnabled(isValid));!
  • 47.
    Advanced Scenario Supercharge 47 
 • RxBinding provides binding for android’s UI widgets. ! Observable.combineLatest(! RxTextView.textChangeEvents(mEmailView),! RxTextView.textChangeEvents(mPasswordView),! (emailChange, passwordChange) -> {! boolean emailOK = emailChange.text().length() >= 3;! boolean passOK = passwordChange.text().length() >= 3;! ! return emailOK && passOK;! })! .compose(bindToLifecycle())! .subscribe(isValid -> mSignIn.setEnabled(isValid));!
  • 48.
    Advanced Scenario Supercharge 48 
 • Combine and evaluate the changes. ! Observable.combineLatest(! RxTextView.textChangeEvents(mEmailView),! RxTextView.textChangeEvents(mPasswordView),! (emailChange, passwordChange) -> {! boolean emailOK = emailChange.text().length() >= 3;! boolean passOK = passwordChange.text().length() >= 3;! ! return emailOK && passOK;! })! .compose(bindToLifecycle())! .subscribe(isValid -> mSignIn.setEnabled(isValid));!
  • 49.
    Advanced Scenario Supercharge 49 
 • Use RxLifeCycle by Trello to properly handle subscriptions. ! Observable.combineLatest(! RxTextView.textChangeEvents(mEmailView),! RxTextView.textChangeEvents(mPasswordView),! (emailChange, passwordChange) -> {! boolean emailOK = emailChange.text().length() >= 3;! boolean passOK = passwordChange.text().length() >= 3;! ! return emailOK && passOK;! })! .compose(bindToLifecycle())! .subscribe(isValid -> mSignIn.setEnabled(isValid));!
  • 50.
    Advanced Scenario Supercharge 50 
 • Enable/Disable Sign in button ! Observable.combineLatest(! RxTextView.textChangeEvents(mEmailView),! RxTextView.textChangeEvents(mPasswordView),! (emailChange, passwordChange) -> {! boolean emailOK = emailChange.text().length() >= 3;! boolean passOK = passwordChange.text().length() >= 3;! ! return emailOK && passOK;! })! .compose(bindToLifecycle())! .subscribe(isValid -> mSignIn.setEnabled(isValid));!
  • 51.
    Advanced Scenario Supercharge 51 • Process services first. Observable<Services> saveServices = apiManager.services()! .compose(rxUtils.applySchedulers())! .map(serviceResponse -> mapServices(serviceResponse))! .doOnNext(services -> saveServices(services));! 

  • 52.
    Advanced Scenario Supercharge 52 • Download data with Retrofit Observable<Services> saveServices = apiManager.services()! .compose(rxUtils.applySchedulers())! .map(serviceResponse -> mapServices(serviceResponse))! .doOnNext(services -> saveServices(services));! 
 ! @GET("/services")! Observable<ServiceResponse> services();!
  • 53.
    Advanced Scenario Supercharge 53 • Apply schedulers Observable<Services> saveServices = apiManager.services()! .compose(rxUtils.applySchedulers())! .map(serviceResponse -> mapServices(serviceResponse))! .doOnNext(services -> saveServices(services));! 
 public <T> Observable.Transformer<T, T> applyDefaultSchedulers() {! return obs-> obs.subscribeOn(Schedulers.io()) ! .observeOn(AndroidSchedulers.mainThread());! }! }!
  • 54.
    Advanced Scenario Supercharge 54 • Apply schedulers Observable<Services> saveServices = apiManager.services()! .compose(rxUtils.applySchedulers())! .map(serviceResponse -> mapServices(serviceResponse))! .doOnNext(services -> saveServices(services));! 
 public <T> Observable.Transformer<T, T> applyDefaultSchedulers() {! return obs-> obs.subscribeOn(Schedulers.io()) ! .observeOn(AndroidSchedulers.mainThread());! }! }!
  • 55.
    Advanced Scenario Supercharge 55 • Apply schedulers Observable<Services> saveServices = apiManager.services()! .compose(rxUtils.applySchedulers())! .map(serviceResponse -> mapServices(serviceResponse))! .doOnNext(services -> saveServices(services));! 
 public <T> Observable.Transformer<T, T> applyDefaultSchedulers() {! return obs-> obs.subscribeOn(Schedulers.io()) ! .observeOn(AndroidSchedulers.mainThread());! }! }!
  • 56.
    Advanced Scenario Supercharge 56 • Map response to domain model Observable<Services> saveServices = apiManager.services()! .compose(rxUtils.applySchedulers())! .map(serviceResponse -> mapServices(serviceResponse))! .doOnNext(services -> saveServices(services));! 
 Transforms the items emitted by an Observable applying a function to each item.
  • 57.
    Advanced Scenario Supercharge 57 • Save data to database Observable<Services> saveServices = apiManager.services()! .compose(rxUtils.applySchedulers())! .map(serviceResponse -> mapServices(serviceResponse))! .doOnNext(services -> saveServices(services));! 

  • 58.
    Advanced Scenario Supercharge 58 • Do things parallel Observable<Services> saveServices = apiManager.services()! .compose(rxUtils.applySchedulers())! .map(serviceResponse -> mapServices(serviceResponse))! .doOnNext(services -> saveServices(services));! 
 Observable<Bills> saveBills = apiManager.bills()! .compose(rxUtils.applySchedulers())! .map(billResponse -> mapBills(billResponse))! .doOnNext(bills -> saveBills(bills));!
  • 59.
    Advanced Scenario Supercharge 59 • Do things parallel Observable.zip(saveServices, saveBills, ! (s, b) -> new LoadingResult(s, b))! .compose(rxComposer.applySchedulers())! .subscribe(loadingResult -> log(loadingResult));!
  • 60.
    Advanced Scenario Supercharge 60 • Do things parallel Observable.zip(saveServices, saveBills, ! (s, b) -> new LoadingResult(s, b))! .compose(rxComposer.applySchedulers())! .subscribe(loadingResult -> log(loadingResult));! static class LoadingResult{! public LoadingResult(Services service, Bills bill) {…}! }!
  • 61.
    Testing •  RxJava asynchronusby nature Supercharge 61
  • 62.
    Testing •  RxJava asynchronusby nature •  At first sight a bit complicated to test Supercharge 62
  • 63.
    Testing •  RxJava asynchronusby nature •  At first sight a bit complicated to test •  Luckily RxJava and RxAndroid come with a couple of tools Supercharge 63
  • 64.
    Testing •  What totest? Supercharge 64
  • 65.
    Testing •  What totest? –  Observables: composition of the various operators Supercharge 65
  • 66.
    Testing •  What totest? –  Observables: composition of the various operators –  How the rest of app behaves while triggered by a subscription Supercharge 66
  • 67.
  • 68.
    Thanks for yourattention! Contact us! Richard Radics Supercharge Lead Android Developer richard.radics@supercharge.io // www.supercharge.io