KEMBAR78
2 презентация rx java+android | PPTX
Reactive Programming
RxJava + Android
Streams (data flow)
Reactive eXtensions ?
Rx Observer pattern
• Observable
• Observer/Subscriber
• Subscription
• Subject
onNext, onCompleted, and onError
new Observer<T>() {
@Override public void onNext(T element) {
// called when Observable «pushes» new event.
}
@Override public void onCompleted() {
// when stream is successfully completed(terminal state)
}
@Override public void onError(Throwable e) {
// bad news, stream is ends with exception (terminal state)
}
};
Rx Basics
http://reactivex.io/
- Emit 0 or N elements
- Fails with exception -> onError()
- Normally completes -> onCompleted()
Observable – Observer Contract
Stream creation
public static Observable<String> helloWorldStream() {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
if (!subscriber.isUnsubscribed()) {
try {
subscriber.onNext("Hello");
subscriber.onNext("World");
subscriber.onCompleted();
} catch (Exception ex) {
subscriber.onError(ex);
}
}
}
});
}
Stream creation
public static Observable<String> helloWorldStream() {
return Observable.create(subscriber -> {
if (!subscriber.isUnsubscribed()) {
try {
subscriber.onNext("Hello");
subscriber.onNext("World");
subscriber.onCompleted();
} catch (Exception ex) {
subscriber.onError(ex);
}
}
});
}
Hello World
@Test public void helloWorldTest() {
Observable<String> stream = helloWorldStream();
stream.subscribe(result -> {
System.out.println(result);
}, err -> {
err.printStackTrace();
});
}
Hello World
@Test public void helloWorldTest() {
Observable<String> stream = helloWorldStream();
stream.subscribe(result -> {
System.out.println(result);
}, err -> {
err.printStackTrace();
});
}
Hello World
@Test public void helloWorldTest() {
Observable<String> stream = helloWorldStream();
stream.subscribe(result -> {
System.out.println(result);
}, err -> {
err.printStackTrace();
});
}
Hello World
@Test public void helloWorldTest() {
Observable<String> stream = helloWorldStream();
stream.subscribe(result -> {
System.out.println(result);
}, err -> {
err.printStackTrace();
});
}
Hello World
@Test public void helloWorldTest() {
Observable<String> stream = helloWorldStream();
stream.subscribe(result -> {
System.out.println(result);
}, err -> {
err.printStackTrace();
});
}
"D:JVMJava JDKbinjava"
Hello
World
Process finished with exit code 0
Hello World
@Test public void helloWorldTest() {
Observable<String> stream = helloWorldStream();
stream
.reduce((prev, newOne) -> prev + " " + newOne )
.subscribe(result -> {
System.out.println(result);
}, err -> {
err.printStackTrace();
});
}
"D:JVMJava JDKbinjava"
Hello World
Process finished with exit code 0
Operators
Creating – create, defer, from, interval, timer, start . . .
Transforming – flatMap, map, scan, groupBy, buffer . . .
Filtering – filter, debounce, distinct, take , first, egnoreElements . . .
Combining – combineLatest, merge, startWith, switch, zip . . .
Conditional & Boolean – contains, skipWhile, takeWhile, takeUntil, all . . .
Math & Agregation – reduce, sum, min, max, count . . .
And others . . .
http://reactivex.io/documentation/operators.html
Creating operators
Observable.just(1, 2, 3, 4);
Observable.from(Arrays.asList(“zero", "one", "two", "three"));
Observable.interval(200, TimeUnit.MILLISECONDS);
Observable.error(new Exception(" :`( "));
Transforming operators
Observable.just(2, 4, 6, 8, 10, 25, 43)
.map(num -> new Pair<Integer, Double>(num, Math.sqrt(num)))
.subscribe(pair -> println("new element is -> " + pair));
Observable.just(2, 4, 6, 8, 10, 25, 43)
.scan((x, y ) -> x + y)
.subscribe(sum -> println("Sum is: (" + sum + ")"));
Filtering operators
Observable.just(2, 30, 22, 5, 60, 1)
.filter(num -> num > 10)
.subscribe(num -> println("Filtered -> " + num));
Combining operators
Observable<Integer> ones = Observable.just(1, 1, 1);
Observable<Integer> twos = Observable.just(2, 2);
Observable
.concat(ones, twos)
.subscribe(res -> System.out.println(res));
Combining operators
Observable<Integer> ones = Observable.just(1, 1, 1);
Observable<Integer> twos = Observable.just(2, 2);
Observable
.combineLatest(ones, twos, (o, t) -> "1 stream ->" + o + "n 2 stream -> " + t)
.subscribe(res -> System.out.println(res));
Conditional & Boolean operators
Observable<Integer> zeros = Observable.just(0, 0, 0).delay(200, MILLISECONDS);
Observable<Integer> nums = Observable.just(1, 2, 3).delay(100, MILLISECONDS);
Observable<Integer> dozens = Observable.just(10, 20, 60).delay(300, MILLISECONDS);
Observable.amb(zeros, nums, dozens)
.subscribe(res -> System.out.println(res)); // prints 1 2 3
RxBus
public class RxBus {
private RxBus() { throw new RuntimeException("Not allowed to create instance ");};
private static final Subject<Object, Object> bus =
new SerializedSubject<>(PublishSubject.create());
public static void send(Object o) {
bus.onNext(o);
}
public static Observable<Object> toObserverable() {
return bus.asObservable();
}
public static boolean hasObservers() {
return bus.hasObservers();
}
public static <T>Observable<T> observeEvent(Class<T> clazz) {
return bus.ofType(clazz).asObservable();
}
}
RxBus
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RxBus.send(new ActivityCreatedEvent());
// . . . more logic here
}
}
RxBus
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RxBus.send(new ActivityCreatedEvent());
// . . . more logic here
}
class SuperBusyService extends Service {
private final CompositeSubscription compSub = new CompositeSubscription();
@Override public void onCreate() {
super.onCreate();
compSub.add(RxBus.observEvent(ActivityCreatedEvent.class)
.subscribe(event -> doSomeLongOperation(), err -> handleErr(err)));
}
@Override public void onDestroy() {
super.onDestroy();
compSub.clear();
}
. . .
Simple Timer
Simple Timer
public void launchTicker() {
final Long secondsDisabled = 60L; // user not allowed to send request for new sms
tickerSub = Observable.interval(1, TimeUnit.SECONDS)
.takeUntil(it -> it >= secondsDisabled -1 /* starts from 0 */ )
.map (sec -> (secondsDisabled - sec))
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe (() -> llSendAgain.isEnabled = false )
.doOnCompleted (() -> llSendAgain.isEnabled = true)
.subscribe(time -> tvTicker.setText(getString(R.string.sms_send_again_timer, time))
, err -> handleError(err));
}
«Do» operators in action
public class HomeScreenPresenter {
final HomeView view;
final HomeInteractor interactor = new HomeInteractorImpl();
public HomeScreenPresenter(HomeView view){ this.view = view; }
public void getClientData(String token) {
view.showProgress();
view.manageSubscription(interactor.loadClientData(token)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(result -> {
view.hideProgress();
view.onDataReady(result);
}, err -> {
view.hideProgress();
view.handleError(err);
})
);
}
}
«Do» operators in action
public class HomeScreenPresenter {
final HomeView view;
final HomeInteractor interactor = new HomeInteractorImpl();
public HomeScreenPresenter(HomeView view){ this.view = view; }
public void getClientData(String token) {
view.showProgress();
view.manageSubscription(interactor.loadClientData(token)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(result -> {
view.hideProgress();
view.onDataReady(result);
}, err -> {
view.hideProgress();
view.handleError(err);
})
);
}
}
«Do» operators in action
public class HomeScreenPresenter {
final HomeView view;
final HomeInteractor interactor = new HomeInteractorImpl();
public HomeScreenPresenter(HomeView view){ this.view = view; }
public void getClientData(String token) {
view.manageSubscription(interactor.loadClientData(token)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.doOnSubscribe(view::showProgress)
.doOnTerminate(view::hideProgress)
.subscribe(result -> { view.onDataReady(result); }, err -> { view.handleError(err);})
);
}
}
«Do» operators in action
public class HomeScreenPresenter {
final HomeView view;
final HomeInteractor interactor = new HomeInteractorImpl();
public HomeScreenPresenter(HomeView view){ this.view = view; }
public void getClientData(String token) {
view.manageSubscription(interactor.loadClientData(token)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.compose(RxUtils.progressBarVisibility(view))
.subscribe(result -> { view.onDataReady(result); }, err -> { view.handleError(err);})
);
}
}
«Do» operators in action
public class HomeScreenPresenter {
final HomeView view;
final HomeInteractor interactor = new HomeInteractorImpl();
public HomeScreenPresenter(HomeView view){ this.view = view; }
public void getClientData(String token) {
view.manageSubscription(interactor.loadClientData(token)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.compose(RxUtils.progressBarVisibility(view))
.subscribe(result -> { view.onDataReady(result); }, err -> { view.handleError(err);})
);
}
}
public static <T> Observable.Transformer<T, T> progressBarVisibility(HomeView view) {
return targetObservable ->
targetObservable.doOnSubscribe(view::showProgress)
.doOnTerminate(view::hideProgress);
}
Validation
final Observable<Boolean> nameObservable = RxTextView.textChanges(edtPassword)
.skip(1)
.map(text -> /* validateInput with side effect */);
final Observable<Boolean> emailObservable = RxTextView.textChanges(edtEmail)
.skip(1)
.map(text -> /* validateInput with side effect */);
final Observable<Boolean> passwordObservable = RxTextView.textChanges(edtPassword)
.skip(1)
.map(text -> /* validateInput with side effect */);
final Subscription combinedSub =
Observable
.combineLatest(nameObservable, emailObservable, passwordObservable,
(name, mail, pass) -> name && mail && pass)
.distinctUntilChanged()
.subscribe(btnProceed::setEnabled);
compositeSubscription.add(combinedSub);
Validation
final Observable<Boolean> nameObservable = RxTextView.textChanges(edtPassword)
.skip(1)
.map(text -> /* validateInput with side effect */);
final Observable<Boolean> emailObservable = RxTextView.textChanges(edtEmail)
.skip(1)
.map(text -> /* validateInput with side effect */);
final Observable<Boolean> passwordObservable = RxTextView.textChanges(edtPassword)
.skip(1)
.map(text -> /* validateInput with side effect */);
final Subscription combinedSub =
Observable
.combineLatest(nameObservable, emailObservable, passwordObservable,
(name, mail, pass) -> name && mail && pass)
.distinctUntilChanged()
.subscribe(btnProceed::setEnabled);
compositeSubscription.add(combinedSub);
Validation
final Observable<Boolean> nameObservable = RxTextView.textChanges(edtPassword)
.skip(1)
.map(text -> /* validateInput with side effect */);
final Observable<Boolean> emailObservable = RxTextView.textChanges(edtEmail)
.skip(1)
.map(text -> /* validateInput with side effect */);
final Observable<Boolean> passwordObservable = RxTextView.textChanges(edtPassword)
.skip(1)
.map(text -> /* validateInput with side effect */);
final Subscription combinedSub =
Observable
.combineLatest(nameObservable, emailObservable, passwordObservable,
(name, mail, pass) -> name && mail && pass)
.distinctUntilChanged()
.subscribe(btnProceed::setEnabled);
compositeSubscription.add(combinedSub);
«Live» search
RxTextView.textChanges(searchEditText)
.flatMap(ApiService::searchItems)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateList, t-> showError());
https://lorentzos.com/improving-ux-with-rxjava-4440a13b157f#.19yawyfss
«Live» search
RxTextView.textChanges(searchEditText)
.debounce(205, TimeUnit.MILLISECONDS)
.flatMap(ApiService::searchItems)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateList, t-> showError());
https://lorentzos.com/improving-ux-with-rxjava-4440a13b157f#.19yawyfss
«Live» search
RxTextView.textChanges(searchEditText)
.debounce(205, TimeUnit.MILLISECONDS)
.switchMap(ApiService::searchItems)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateList, t-> showError());
https://lorentzos.com/improving-ux-with-rxjava-4440a13b157f#.19yawyfss
«Live» search
RxTextView.textChanges(searchEditText)
.debounce(205, TimeUnit.MILLISECONDS)
.switchMap(ApiService::searchItems)
.onErrorResumeNext(err -> Observable.empty())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateList, t-> showError());
https://lorentzos.com/improving-ux-with-rxjava-4440a13b157f#.19yawyfss
«Live» search
RxTextView.textChanges(searchEditText)
.debounce(205, TimeUnit.MILLISECONDS)
.switchMap(ApiService::searchItems)
.retryWhen(new NetworkConnectivity())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateList, t-> showError());
https://lorentzos.com/improving-ux-with-rxjava-4440a13b157f#.19yawyfss
«Live» search
RxTextView.textChanges(searchEditText)
.debounce(205, TimeUnit.MILLISECONDS)
.switchMap(ApiService::searchItems)
.retryWhen(new NetworkConnectivityIncremental(context, 5, 15, SECONDS))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateList, t-> showError());
https://lorentzos.com/improving-ux-with-rxjava-4440a13b157f#.19yawyfss
Easy concurrency
NetApiService.loadDocument(docId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
// want find matches or smth ASAP
.map(data -> MatchFinder.find(data, PATTERN))
// work done, can swith on low priority 'IO' pool
.observeOn(Schedulers.io())
.doOnNext(processedData -> DataProvider.saveProcessedDocument(docId, processedData))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(/* do something with result */);
https://twitter.com/mr_art_Core

2 презентация rx java+android

  • 1.
  • 3.
  • 4.
  • 5.
    Rx Observer pattern •Observable • Observer/Subscriber • Subscription • Subject
  • 6.
    onNext, onCompleted, andonError new Observer<T>() { @Override public void onNext(T element) { // called when Observable «pushes» new event. } @Override public void onCompleted() { // when stream is successfully completed(terminal state) } @Override public void onError(Throwable e) { // bad news, stream is ends with exception (terminal state) } };
  • 7.
  • 8.
    - Emit 0or N elements - Fails with exception -> onError() - Normally completes -> onCompleted() Observable – Observer Contract
  • 9.
    Stream creation public staticObservable<String> helloWorldStream() { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { if (!subscriber.isUnsubscribed()) { try { subscriber.onNext("Hello"); subscriber.onNext("World"); subscriber.onCompleted(); } catch (Exception ex) { subscriber.onError(ex); } } } }); }
  • 10.
    Stream creation public staticObservable<String> helloWorldStream() { return Observable.create(subscriber -> { if (!subscriber.isUnsubscribed()) { try { subscriber.onNext("Hello"); subscriber.onNext("World"); subscriber.onCompleted(); } catch (Exception ex) { subscriber.onError(ex); } } }); }
  • 11.
    Hello World @Test publicvoid helloWorldTest() { Observable<String> stream = helloWorldStream(); stream.subscribe(result -> { System.out.println(result); }, err -> { err.printStackTrace(); }); }
  • 12.
    Hello World @Test publicvoid helloWorldTest() { Observable<String> stream = helloWorldStream(); stream.subscribe(result -> { System.out.println(result); }, err -> { err.printStackTrace(); }); }
  • 13.
    Hello World @Test publicvoid helloWorldTest() { Observable<String> stream = helloWorldStream(); stream.subscribe(result -> { System.out.println(result); }, err -> { err.printStackTrace(); }); }
  • 14.
    Hello World @Test publicvoid helloWorldTest() { Observable<String> stream = helloWorldStream(); stream.subscribe(result -> { System.out.println(result); }, err -> { err.printStackTrace(); }); }
  • 15.
    Hello World @Test publicvoid helloWorldTest() { Observable<String> stream = helloWorldStream(); stream.subscribe(result -> { System.out.println(result); }, err -> { err.printStackTrace(); }); } "D:JVMJava JDKbinjava" Hello World Process finished with exit code 0
  • 16.
    Hello World @Test publicvoid helloWorldTest() { Observable<String> stream = helloWorldStream(); stream .reduce((prev, newOne) -> prev + " " + newOne ) .subscribe(result -> { System.out.println(result); }, err -> { err.printStackTrace(); }); } "D:JVMJava JDKbinjava" Hello World Process finished with exit code 0
  • 17.
    Operators Creating – create,defer, from, interval, timer, start . . . Transforming – flatMap, map, scan, groupBy, buffer . . . Filtering – filter, debounce, distinct, take , first, egnoreElements . . . Combining – combineLatest, merge, startWith, switch, zip . . . Conditional & Boolean – contains, skipWhile, takeWhile, takeUntil, all . . . Math & Agregation – reduce, sum, min, max, count . . . And others . . . http://reactivex.io/documentation/operators.html
  • 18.
    Creating operators Observable.just(1, 2,3, 4); Observable.from(Arrays.asList(“zero", "one", "two", "three")); Observable.interval(200, TimeUnit.MILLISECONDS); Observable.error(new Exception(" :`( "));
  • 19.
    Transforming operators Observable.just(2, 4,6, 8, 10, 25, 43) .map(num -> new Pair<Integer, Double>(num, Math.sqrt(num))) .subscribe(pair -> println("new element is -> " + pair)); Observable.just(2, 4, 6, 8, 10, 25, 43) .scan((x, y ) -> x + y) .subscribe(sum -> println("Sum is: (" + sum + ")"));
  • 20.
    Filtering operators Observable.just(2, 30,22, 5, 60, 1) .filter(num -> num > 10) .subscribe(num -> println("Filtered -> " + num));
  • 21.
    Combining operators Observable<Integer> ones= Observable.just(1, 1, 1); Observable<Integer> twos = Observable.just(2, 2); Observable .concat(ones, twos) .subscribe(res -> System.out.println(res));
  • 22.
    Combining operators Observable<Integer> ones= Observable.just(1, 1, 1); Observable<Integer> twos = Observable.just(2, 2); Observable .combineLatest(ones, twos, (o, t) -> "1 stream ->" + o + "n 2 stream -> " + t) .subscribe(res -> System.out.println(res));
  • 23.
    Conditional & Booleanoperators Observable<Integer> zeros = Observable.just(0, 0, 0).delay(200, MILLISECONDS); Observable<Integer> nums = Observable.just(1, 2, 3).delay(100, MILLISECONDS); Observable<Integer> dozens = Observable.just(10, 20, 60).delay(300, MILLISECONDS); Observable.amb(zeros, nums, dozens) .subscribe(res -> System.out.println(res)); // prints 1 2 3
  • 25.
    RxBus public class RxBus{ private RxBus() { throw new RuntimeException("Not allowed to create instance ");}; private static final Subject<Object, Object> bus = new SerializedSubject<>(PublishSubject.create()); public static void send(Object o) { bus.onNext(o); } public static Observable<Object> toObserverable() { return bus.asObservable(); } public static boolean hasObservers() { return bus.hasObservers(); } public static <T>Observable<T> observeEvent(Class<T> clazz) { return bus.ofType(clazz).asObservable(); } }
  • 26.
    RxBus public class MainActivityextends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RxBus.send(new ActivityCreatedEvent()); // . . . more logic here } }
  • 27.
    RxBus public class MainActivityextends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RxBus.send(new ActivityCreatedEvent()); // . . . more logic here } class SuperBusyService extends Service { private final CompositeSubscription compSub = new CompositeSubscription(); @Override public void onCreate() { super.onCreate(); compSub.add(RxBus.observEvent(ActivityCreatedEvent.class) .subscribe(event -> doSomeLongOperation(), err -> handleErr(err))); } @Override public void onDestroy() { super.onDestroy(); compSub.clear(); } . . .
  • 28.
  • 29.
    Simple Timer public voidlaunchTicker() { final Long secondsDisabled = 60L; // user not allowed to send request for new sms tickerSub = Observable.interval(1, TimeUnit.SECONDS) .takeUntil(it -> it >= secondsDisabled -1 /* starts from 0 */ ) .map (sec -> (secondsDisabled - sec)) .observeOn(AndroidSchedulers.mainThread()) .doOnSubscribe (() -> llSendAgain.isEnabled = false ) .doOnCompleted (() -> llSendAgain.isEnabled = true) .subscribe(time -> tvTicker.setText(getString(R.string.sms_send_again_timer, time)) , err -> handleError(err)); }
  • 30.
    «Do» operators inaction public class HomeScreenPresenter { final HomeView view; final HomeInteractor interactor = new HomeInteractorImpl(); public HomeScreenPresenter(HomeView view){ this.view = view; } public void getClientData(String token) { view.showProgress(); view.manageSubscription(interactor.loadClientData(token) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(result -> { view.hideProgress(); view.onDataReady(result); }, err -> { view.hideProgress(); view.handleError(err); }) ); } }
  • 31.
    «Do» operators inaction public class HomeScreenPresenter { final HomeView view; final HomeInteractor interactor = new HomeInteractorImpl(); public HomeScreenPresenter(HomeView view){ this.view = view; } public void getClientData(String token) { view.showProgress(); view.manageSubscription(interactor.loadClientData(token) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(result -> { view.hideProgress(); view.onDataReady(result); }, err -> { view.hideProgress(); view.handleError(err); }) ); } }
  • 32.
    «Do» operators inaction public class HomeScreenPresenter { final HomeView view; final HomeInteractor interactor = new HomeInteractorImpl(); public HomeScreenPresenter(HomeView view){ this.view = view; } public void getClientData(String token) { view.manageSubscription(interactor.loadClientData(token) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .doOnSubscribe(view::showProgress) .doOnTerminate(view::hideProgress) .subscribe(result -> { view.onDataReady(result); }, err -> { view.handleError(err);}) ); } }
  • 33.
    «Do» operators inaction public class HomeScreenPresenter { final HomeView view; final HomeInteractor interactor = new HomeInteractorImpl(); public HomeScreenPresenter(HomeView view){ this.view = view; } public void getClientData(String token) { view.manageSubscription(interactor.loadClientData(token) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .compose(RxUtils.progressBarVisibility(view)) .subscribe(result -> { view.onDataReady(result); }, err -> { view.handleError(err);}) ); } }
  • 34.
    «Do» operators inaction public class HomeScreenPresenter { final HomeView view; final HomeInteractor interactor = new HomeInteractorImpl(); public HomeScreenPresenter(HomeView view){ this.view = view; } public void getClientData(String token) { view.manageSubscription(interactor.loadClientData(token) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .compose(RxUtils.progressBarVisibility(view)) .subscribe(result -> { view.onDataReady(result); }, err -> { view.handleError(err);}) ); } } public static <T> Observable.Transformer<T, T> progressBarVisibility(HomeView view) { return targetObservable -> targetObservable.doOnSubscribe(view::showProgress) .doOnTerminate(view::hideProgress); }
  • 35.
    Validation final Observable<Boolean> nameObservable= RxTextView.textChanges(edtPassword) .skip(1) .map(text -> /* validateInput with side effect */); final Observable<Boolean> emailObservable = RxTextView.textChanges(edtEmail) .skip(1) .map(text -> /* validateInput with side effect */); final Observable<Boolean> passwordObservable = RxTextView.textChanges(edtPassword) .skip(1) .map(text -> /* validateInput with side effect */); final Subscription combinedSub = Observable .combineLatest(nameObservable, emailObservable, passwordObservable, (name, mail, pass) -> name && mail && pass) .distinctUntilChanged() .subscribe(btnProceed::setEnabled); compositeSubscription.add(combinedSub);
  • 36.
    Validation final Observable<Boolean> nameObservable= RxTextView.textChanges(edtPassword) .skip(1) .map(text -> /* validateInput with side effect */); final Observable<Boolean> emailObservable = RxTextView.textChanges(edtEmail) .skip(1) .map(text -> /* validateInput with side effect */); final Observable<Boolean> passwordObservable = RxTextView.textChanges(edtPassword) .skip(1) .map(text -> /* validateInput with side effect */); final Subscription combinedSub = Observable .combineLatest(nameObservable, emailObservable, passwordObservable, (name, mail, pass) -> name && mail && pass) .distinctUntilChanged() .subscribe(btnProceed::setEnabled); compositeSubscription.add(combinedSub);
  • 37.
    Validation final Observable<Boolean> nameObservable= RxTextView.textChanges(edtPassword) .skip(1) .map(text -> /* validateInput with side effect */); final Observable<Boolean> emailObservable = RxTextView.textChanges(edtEmail) .skip(1) .map(text -> /* validateInput with side effect */); final Observable<Boolean> passwordObservable = RxTextView.textChanges(edtPassword) .skip(1) .map(text -> /* validateInput with side effect */); final Subscription combinedSub = Observable .combineLatest(nameObservable, emailObservable, passwordObservable, (name, mail, pass) -> name && mail && pass) .distinctUntilChanged() .subscribe(btnProceed::setEnabled); compositeSubscription.add(combinedSub);
  • 38.
  • 39.
  • 40.
  • 41.
    «Live» search RxTextView.textChanges(searchEditText) .debounce(205, TimeUnit.MILLISECONDS) .switchMap(ApiService::searchItems) .onErrorResumeNext(err-> Observable.empty()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::updateList, t-> showError()); https://lorentzos.com/improving-ux-with-rxjava-4440a13b157f#.19yawyfss
  • 42.
    «Live» search RxTextView.textChanges(searchEditText) .debounce(205, TimeUnit.MILLISECONDS) .switchMap(ApiService::searchItems) .retryWhen(newNetworkConnectivity()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::updateList, t-> showError()); https://lorentzos.com/improving-ux-with-rxjava-4440a13b157f#.19yawyfss
  • 43.
    «Live» search RxTextView.textChanges(searchEditText) .debounce(205, TimeUnit.MILLISECONDS) .switchMap(ApiService::searchItems) .retryWhen(newNetworkConnectivityIncremental(context, 5, 15, SECONDS)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::updateList, t-> showError()); https://lorentzos.com/improving-ux-with-rxjava-4440a13b157f#.19yawyfss
  • 44.
    Easy concurrency NetApiService.loadDocument(docId) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) // wantfind matches or smth ASAP .map(data -> MatchFinder.find(data, PATTERN)) // work done, can swith on low priority 'IO' pool .observeOn(Schedulers.io()) .doOnNext(processedData -> DataProvider.saveProcessedDocument(docId, processedData)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(/* do something with result */);
  • 45.