What it means to be Reactive?
RxJava for Android
Constantine Mars
Senior Android Developer @ DataArt
GDG Dnipro and JUG Dnepr
–Ivan Morgillo, Alter Ego solutions, speech on DroidCon Berlin’2015
“A piece of cake, you know”
#dfua
Faces of the Reactive Programming World
Ben Christensen, Netflix - RxJava
Erik Meijer, Applied Duality - Rx.NET
Jake Wharton, Square - RxAndroid
Ivan Morgillo, Alter Ego - first book
about RxAndroid
Fundamentals
The basic concepts behind Rx
#dfua
Time to meditate...
Everything is a stream…
#dfua
The one who is listening is Observer
And the other one, who is emitting events, is Subject, or Observable
*Illustration from O’Reilly® HeadFirst “Design Patterns” book:
#dfua
This is well known interface in for both Android and Desktop developers
Observer = Listener
t.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Timber.d("something");
}
});
.JAVA
#dfua
We will use it throughout presentation
Lambda syntax
t.setOnClickListener(v -> Timber.d("something"));
.JAVA
RxJava. Observable & Observer
Basics
#dfua
It’s the source of events
Observable
rx.Observable<Integer> observable = rx.Observable.create(
new rx.Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
for (int i = 0; i < N; i++) {
Integer integer = random.nextInt(MAX);
subscriber.onNext(integer);
}
subscriber.onCompleted();
}
});
.JAVA
Be aware: there is java.util.Observable besides rx.Observable - they’re not the same
#dfua
It’s the source of events. It handles subscriptions through OnSubscribe callback
Observable
rx.Observable<Integer> observable = rx.Observable.create(
new rx.Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
for (int i = 0; i < N; i++) {
Integer integer = random.nextInt(MAX);
subscriber.onNext(integer);
}
subscriber.onCompleted();
}
});
.JAVA
Be aware: there is java.util.Observable besides rx.Observable - they’re not the same
#dfua
It’s the source of events. It handles subscriptions through OnSubscribe callback.
When observer subscribes, it is named subscriber inside of a call()
Observable
rx.Observable<Integer> observable = rx.Observable.create(
new rx.Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
for (int i = 0; i < N; i++) {
Integer integer = random.nextInt(MAX);
subscriber.onNext(integer);
}
subscriber.onCompleted();
}
});
.JAVA
Be aware: there is java.util.Observable besides rx.Observable - they’re not the same
#dfua
It’s the source of events. It handles subscriptions through OnSubscribe callback.
When observer subscribes, it is named subscriber inside of a call()
Observable
rx.Observable<Integer> observable = rx.Observable.create(
new rx.Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
for (int i = 0; i < N; i++) {
Integer integer = random.nextInt(MAX);
subscriber.onNext(integer);
}
subscriber.onCompleted();
}
});
.JAVA
Be aware: there is java.util.Observable besides rx.Observable - they’re not the same
#dfua
Observer
rx.Observer<Integer> observer = new rx.Observer<Integer>() {
@Override
public void onCompleted() {
display.show("completed");
}
@Override
public void onError(Throwable e) {
display.show("error: " + e.getMessage());
}
@Override
public void onNext(Integer integer) {
display.show("next: " + integer);
}
};
observable.subscribe(observer);
.JAVA
It’s the bunch of Reactive callbacks that should be registered through
subscription.
#dfua
It’s the bunch of Reactive callbacks that should be registered through
subscription. And handles incoming onNext(), onCompleted() and onError() from
Observable
Observer
rx.Observer<Integer> observer = new rx.Observer<Integer>() {
@Override
public void onCompleted() {
display.show("completed");
}
@Override
public void onError(Throwable e) {
display.show("error: " + e.getMessage());
}
@Override
public void onNext(Integer integer) {
display.show("next: " + integer);
}
};
observable.subscribe(observer);
.JAVA
#dfua
But to make magic we need one more thing...
Observer
rx.Observer<Integer> observer = new rx.Observer<Integer>() {
@Override
public void onCompleted() {
display.show("completed");
}
@Override
public void onError(Throwable e) {
display.show("error: " + e.getMessage());
}
@Override
public void onNext(Integer integer) {
display.show("next: " + integer);
}
};
observable.subscribe(observer);
.JAVA
#dfua
To subscribe. This means creating Subscription.
Subscription
Subscription subscription = observable.subscribe(observer);
...
if(!subscription.isUnsubscribed()) {
subscription.unsubscribe();
}
.JAVA
#dfua
To subscribe. This means creating Subscription.
In fact Subscription class is rarely used, but can be useful to unsubscribe when we
don’t need to receive events
Subscription
Subscription subscription = observable.subscribe(observer);
...
if(!subscription.isUnsubscribed()) {
subscription.unsubscribe();
}
.JAVA
#dfua
Looks more readable, isn’t it?
At least takes one screen, not three :)
Observable + Observer with lambdas
rx.Observable<Integer> observable = rx.Observable.create(subscriber -> {
for (int i = 0; i < N; i++)
subscriber.onNext(random.nextInt(MAX));
subscriber.onCompleted();
});
observable.subscribe(
integer -> display.show("next: " + integer),
throwable -> display.show("error: " + throwable.getMessage()),
() -> display.show("completed"));
.JAVA
#dfua
Reactive Systems are:
*Check ReactiveManifesto.org for detailed definitions:
Message Driven
Responsive
Resilient
Scalable (Elastic)
From everything, ...even from air :)
Creating Observables
#dfua
Observable.from()
ENTER FILENAME/LANG
ArrayList<Integer> arrayList = new ArrayList<>();
int MAX_N = random.nextInt(12) + 5;
for (int i = 0; i < MAX_N; i++) arrayList.add(random.nextInt(MAX));
rx.Observable.from(arrayList)
.subscribe(
integer -> display.show("next: " + integer),
throwable -> display.show("error: " + throwable.getMessage()),
() -> display.show("complete"));
.JAVA
#dfua
Observable.just()
ENTER FILENAME/LANG
private List<Integer> generate() {
Random r = new Random();
int n = r.nextInt(5) + 5;
ArrayList<Integer> a = new ArrayList<>();
for (int i = 0; i < n; i++)
a.add(r.nextInt(100));
return a;
}
public void just() {
rx.Observable.just(generate())
.subscribe(integer -> display.show("next: " + integer),
throwable -> display.show("error: " + throwable.getMessage()),
() -> display.show("complete"));
}
.JAVA
#dfua
Observable.interval()
Random r = new Random();
rx.Observable.interval(2, TimeUnit.SECONDS)
.map(t -> new long[]{t, r.nextInt(100)})
.limit(5)
.subscribe(
tuple -> display.show("next: " + Arrays.toString(tuple)),
throwable -> {
},
() -> display.show("complete"));
.JAVA
#dfua
Retrofit
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.build();
GitHubService service = restAdapter.create(GitHubService.class);
// Retrofit can return observable which we handle as any other observable
service.listRepos("c-mars")
.flatMap(Observable::from)
.limit(10)
.subscribe(repo -> display.show("next: " + repo.toString()),
throwable -> display.show("error: " + throwable.getMessage()),
() -> display.show("completed"));
.JAVA
#dfua
RxBindings
Button button;
...
RxView.clicks(button)
.map(v -> ++counter)
.debounce(500, TimeUnit.MILLISECONDS)
.subscribe(c -> display.show("button " + c));
.JAVA
Filtering, conditions
RxJava Goods
#dfua
Blocking
private final AmmeterReadings[] data = {
new AmmeterReadings(1, 0.5),
...
};
private static float getMaxValue(AmmeterReadings[] data) {
return MathObservable.max(rx.Observable.from(data)
.map(AmmeterReadings::getCurrent))
.toBlocking().firstOrDefault(0L);
}
.JAVA
By default rx.Observable is async. But it can be converted to BlockingObservable
and return result in-place, using functional computations.
#dfua
first, last, take, orDefault
private final AmmeterReadings[] data = {
new AmmeterReadings(1, 0.5),
...
};
private static float getMaxValue(AmmeterReadings[] data) {
return MathObservable.max(rx.Observable.from(data)
.map(AmmeterReadings::getCurrent))
.toBlocking().firstOrDefault(0L);
}
.JAVA
We can take first, last or any item from BlockingObservable. If it’s empty, we can
define default value.
#dfua
take from Observable
private final AmmeterReadings[] data = {
new AmmeterReadings(1, 0.5),
...
};
private static float getMaxValue(AmmeterReadings[] data) {
return MathObservable.max( rx.Observable.from(data)
.map(AmmeterReadings::getCurrent)
.takeLast(5) )
.toBlocking().firstOrDefault(0L);
}
.JAVA
rx.Observable (non-blocking) provides method take() to take multiple items from
stream.
#dfua
singleOrDefault
rx.Observable.range(0, 0)
.singleOrDefault(-1)
.forEach(i -> getDisplay().show("single:" + i));
.JAVA
Check whether rx.Observable contains only one event/item.
#dfua
defaultIfEmpty
rx.Observable.range(0, max)
.defaultIfEmpty(999)
.forEach(i -> getDisplay().show("range 0->" + max + ", value (999 if empty):"
+ String.valueOf(i)));
.JAVA
Almost the same as singleOrDefault
#dfua
toIterable
final Integer[] data = {200, 4, 145, -1, 10, -12, 80};
Iterable<Integer> iterable = rx.Observable.from(data)
.toBlocking().toIterable();
for (Integer i : iterable) {
display.show("iterable:" + i.toString());
}
.JAVA
BlockingObservable.toIterable() converts rx.Observable to collection
#dfua
forEach
final Integer[] data = {200, 4, 145, -1, 10, -12, 80};
rx.Observable.from(data)
.forEach(i -> display.show("iterable:" + i.toString()));
.JAVA
forEach() is just shorcut to .subscribe()
#dfua
takeUntil
rx.Observable.range(0, 10)
.takeUntil(i -> i == 5)
.forEach(i -> getDisplay().show(String.valueOf(i)));
// out: 0, 1, 2, 3, 4, 5
.JAVA
Just a variant of take(), which completes when condition matches.
#dfua
contains
rx.Observable.range(0, max)
.contains(2)
.forEach(i -> getDisplay().show("range: " + 0 + "->" + max + ",contains 2: " +
String.valueOf(i)));
// out: true (or false)
.JAVA
Check whether stream contains certain value
#dfua
filter
rx.Observable.range(0, 10)
.filter(i -> i > 5 && i < 9 )
.forEach(i -> getDisplay().show(i));
// out: 6, 7, 8
.JAVA
Like takeUntil, just filter :)
#dfua
debounce
long[] times = {3, 2, 1, 5, 2, 6};
rx.Observable<Pair<Integer, Long>> observable = rx.Observable.create(subscriber -> {
int sz = times.length;
for (int i = 0; i < sz; i++) {
try {
long t = times[i];
TimeUnit.MILLISECONDS.sleep(t);
subscriber.onNext(new Pair<>(i, t));
} catch (InterruptedException e) {
subscriber.onError(e);
}
}
subscriber.onCompleted();
});
observable.debounce(4, TimeUnit.MILLISECONDS)
.subscribe(pair -> getDisplay().show("out: value=" + pair.first + ", time=" +
pair.second));
.JAVA
#dfua
sample
long[] times = {3, 2, 1, 5, 4, 3, 1};
rx.Observable<Pair<Integer, Long>> observable = rx.Observable.create(subscriber -> {
int sz = times.length;
for (int i = 0; i < sz; i++) {
try {
long t = times[i];
TimeUnit.MILLISECONDS.sleep(t * 10);
subscriber.onNext(new Pair<>(i, t));
} catch (InterruptedException e) {
subscriber.onError(e);
}
}
subscriber.onCompleted();
});
observable.sample(40, TimeUnit.MILLISECONDS)
.subscribe(pair -> getDisplay().show("out: value=" + pair.first + "; time=" +
pair.second));
.JAVA
Merge and combine
RxJava Goods
#dfua
merge
rx.Observable first = Observable.range(0, 5); //int[]
rx.Observable second = Observable.from(new String[]{"one", "two", "three", "four",
"five"}); //String[]
rx.Observable.merge(first, second)
.forEach(item -> getDisplay().show(item.toString()));
.JAVA
Merges items from separate rx.Observables to single stream
#dfua
zip
rx.Observable<Integer> first = Observable.range(0, 5); //int[]
rx.Observable<String> second = Observable.from(new String[]{"one", "two",
"three", "four", "five"}); //String[]
rx.Observable.zip(first, second, (i, s) -> new Pair(s, i))
.forEach(pair -> getDisplay().show(pair.toString()));
.JAVA
Merges items from separate rx.Observables to single stream using combining
function.
RxJava Error Handling
#dfua
retry
rx.Observable<Integer> canFail = rx.Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
for (int i = 0; i < 6; i++) {
switch (i) {
case 3:
if (!failedOnce) {
failedOnce = true;
subscriber.onError(new Error());
return;
}
break;
case 5:
subscriber.onError(new Throwable());
return;
}
subscriber.onNext(i);
}
subscriber.onCompleted();
}
});
.JAVA
#dfua
retry
canFail.retry((integer, throwable) -> {
boolean retry = (throwable instanceof Error);
getDisplay().show("retry, errors: " + integer);
return retry;
})
.subscribe(i -> {
getDisplay().show(i);
}, throwable -> {
getDisplay().show("error: " + throwable.getMessage());
});
.JAVA
#dfua
retry
In case of error we can check condition in retry() and then
re-subscribe and try once more
Math and aggregate
RxJava Goods
#dfua
MathObservable
private final AmmeterReadings[] data = {
new AmmeterReadings(1, 0.5),
...
};
private static float getMaxValue(AmmeterReadings[] data) {
return MathObservable.max(rx.Observable.from(data)
.map(AmmeterReadings::getCurrent))
.toBlocking().firstOrDefault(0L);
}
.JAVA
Plugin MathObservable: compile 'io.reactivex:rxjava-math:1.0.0'
max, average, sum, count
#dfua
Average
rx.Observable<Integer> integers = rx.Observable.range(0, 10);
MathObservable.averageInteger(integers).subscribe(avg -> {
getDisplay().show(avg);
});
.JAVA
Many methods of MathObservable has type-aware alternatives
#dfua
reduce
rx.Observable.range(0, 10).reduce((a, b) -> {
int c = a + b;
getDisplay().show("reduce: a=" + a + " + " + b + " = " + c);
return c;
}).forEach(value -> getDisplay().show("result: " + value));
.JAVA
Classic reduce operation, common for all functional programming languages
Ubiquitous mediums that like actors can play any role
RxJava Subjects
#dfua
Creating Subjects
PublishSubject<String> subject = PublishSubject.create();
example(subject);
…
ReplaySubject<String> subject = ReplaySubject.createWithSize(2);
example(subject);
.JAVA
Subjects have method .create() for this. ReplaySubject can also be created with
predefined number of events to replay on subscription.
#dfua
Example code
private void example(Subject<String, String> subject) {
subject.onNext("before 1");
subject.onNext("before 2");
subject.onNext("before 3");
subject.onNext("before 4");
subject.subscribe(s -> getDisplay().show("subscribed: " + s));
subject.onNext("after 5");
subject.onNext("after 6");
subject.onNext("after 7");
subject.onNext("after 8");
subject.onCompleted();
}
.JAVA
Subject can act both like Observable and Observer. So we can call .onNext,
.onComplete manually and trigger subscription callbacks
#dfua
Subjects behaviour
PublishSubject
Is just a proxy for events
AsyncSubject
Replays only last event onComplete
ReplaySubject
Replays last N events and
then proxies the same as
Publish
BehaviorSubject
Replays only last event and
then proxies the same as
Publish
#dfua
ReactiveX Diagrams
In a hour of despair - seek inspiration at ReactiveX.io
RxJava Schedulers
#dfua
Schedulers
rx.Observable.from(readFromFile(context))
.subscribeOn(Schedulers.io())
.forEach(line -> textView.append("n" + line));
.JAVA
By default rx.Observable is single-threaded. Here come Schedulers to hide
threading and synchronization behind the functional interface.
Just call .subscribeOn() and define which kind of threading you want
#dfua
Schedulers
rx.Observable source = rx.Observable.range(0, 10).map(integer -> {
List<Integer> outs = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
outs.add((int) Math.pow(i, j));
}
}
return outs;
}).flatMap(Observable::from);
MathObservable.sumInteger(source)
.subscribeOn(Schedulers.computation())
.subscribe(integer -> textView.setText("final sum: " + integer.toString()));
.JAVA
#dfua
Android UI
MathObservable.sumInteger(source)
.subscribeOn(Schedulers.computation())
.subscribe(integer -> textView.setText("final sum: " + integer.toString()));
.JAVA
Scheduler move execution to another appropriate thread. But when we try to
update UI from this chain - something bad happens...
#dfua
Android UI
MathObservable.sumInteger(source)
.subscribeOn(Schedulers.computation())
.subscribe(integer -> textView.setText("final sum: " + integer.toString()));
.JAVA
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the
original thread that created a view hierarchy can touch its views.
E/AndroidRuntime: at
android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556)
E/AndroidRuntime: at
android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:942)
E/AndroidRuntime: at android.view.ViewGroup.invalidateChild(ViewGroup.java:5081)
E/AndroidRuntime: at android.view.View.invalidateInternal(View.java:12713)
E/AndroidRuntime: at android.view.View.invalidate(View.java:12677)
E/AndroidRuntime: at android.view.View.invalidate(View.java:12661)
...
CONSOLE
Comes to play
RxAndroid
#dfua
Relationship to RxJava
#dfua
AndroidSchedulers
rx.Observable.from(readFromFile(context))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.forEach(line -> textView.append("n" + line));
.JAVA
.subscribeOn defines thread on which computations run,
.observeOn defines thread on which rx.Observer callbacks will run
#dfua
Activity Lifecycle
// Activity
private Subscription subscription;
protected void onCreate(Bundle savedInstanceState) {
this.subscription = observable.subscribe(this);
}
...
protected void onDestroy() {
this.subscription.unsubscribe();
super.onDestroy();
}
.JAVA
Use subscription or CompositeSubscription
RxJava
Journey comes to end
#dfua
Where to look?
● JavaDoc: http://reactivex.io/RxJava/javadoc/rx/Observable.html
● List of Additional Reading from RxJava Wiki:
https://github.com/ReactiveX/RxJava/wiki/Additional-Reading
● RxJava Essentials by Ivan Morgillo:
https://www.packtpub.com/application-development/rxjava-essentials
● RxMarbles - interactive diagrams: http://rxmarbles.com/
#dfua
ReactiveX RxJava Additional Reading
Thank you!
Questions?
+ConstantineMars
dataart.com.ua
dnipro.gdg.org.ua

RxJava for Android - GDG DevFest Ukraine 2015

  • 1.
    What it meansto be Reactive? RxJava for Android Constantine Mars Senior Android Developer @ DataArt GDG Dnipro and JUG Dnepr
  • 2.
    –Ivan Morgillo, AlterEgo solutions, speech on DroidCon Berlin’2015 “A piece of cake, you know”
  • 3.
    #dfua Faces of theReactive Programming World Ben Christensen, Netflix - RxJava Erik Meijer, Applied Duality - Rx.NET Jake Wharton, Square - RxAndroid Ivan Morgillo, Alter Ego - first book about RxAndroid
  • 4.
  • 5.
  • 6.
    #dfua The one whois listening is Observer And the other one, who is emitting events, is Subject, or Observable *Illustration from O’Reilly® HeadFirst “Design Patterns” book:
  • 7.
    #dfua This is wellknown interface in for both Android and Desktop developers Observer = Listener t.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Timber.d("something"); } }); .JAVA
  • 8.
    #dfua We will useit throughout presentation Lambda syntax t.setOnClickListener(v -> Timber.d("something")); .JAVA
  • 9.
    RxJava. Observable &Observer Basics
  • 10.
    #dfua It’s the sourceof events Observable rx.Observable<Integer> observable = rx.Observable.create( new rx.Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { for (int i = 0; i < N; i++) { Integer integer = random.nextInt(MAX); subscriber.onNext(integer); } subscriber.onCompleted(); } }); .JAVA Be aware: there is java.util.Observable besides rx.Observable - they’re not the same
  • 11.
    #dfua It’s the sourceof events. It handles subscriptions through OnSubscribe callback Observable rx.Observable<Integer> observable = rx.Observable.create( new rx.Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { for (int i = 0; i < N; i++) { Integer integer = random.nextInt(MAX); subscriber.onNext(integer); } subscriber.onCompleted(); } }); .JAVA Be aware: there is java.util.Observable besides rx.Observable - they’re not the same
  • 12.
    #dfua It’s the sourceof events. It handles subscriptions through OnSubscribe callback. When observer subscribes, it is named subscriber inside of a call() Observable rx.Observable<Integer> observable = rx.Observable.create( new rx.Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { for (int i = 0; i < N; i++) { Integer integer = random.nextInt(MAX); subscriber.onNext(integer); } subscriber.onCompleted(); } }); .JAVA Be aware: there is java.util.Observable besides rx.Observable - they’re not the same
  • 13.
    #dfua It’s the sourceof events. It handles subscriptions through OnSubscribe callback. When observer subscribes, it is named subscriber inside of a call() Observable rx.Observable<Integer> observable = rx.Observable.create( new rx.Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { for (int i = 0; i < N; i++) { Integer integer = random.nextInt(MAX); subscriber.onNext(integer); } subscriber.onCompleted(); } }); .JAVA Be aware: there is java.util.Observable besides rx.Observable - they’re not the same
  • 14.
    #dfua Observer rx.Observer<Integer> observer =new rx.Observer<Integer>() { @Override public void onCompleted() { display.show("completed"); } @Override public void onError(Throwable e) { display.show("error: " + e.getMessage()); } @Override public void onNext(Integer integer) { display.show("next: " + integer); } }; observable.subscribe(observer); .JAVA It’s the bunch of Reactive callbacks that should be registered through subscription.
  • 15.
    #dfua It’s the bunchof Reactive callbacks that should be registered through subscription. And handles incoming onNext(), onCompleted() and onError() from Observable Observer rx.Observer<Integer> observer = new rx.Observer<Integer>() { @Override public void onCompleted() { display.show("completed"); } @Override public void onError(Throwable e) { display.show("error: " + e.getMessage()); } @Override public void onNext(Integer integer) { display.show("next: " + integer); } }; observable.subscribe(observer); .JAVA
  • 16.
    #dfua But to makemagic we need one more thing... Observer rx.Observer<Integer> observer = new rx.Observer<Integer>() { @Override public void onCompleted() { display.show("completed"); } @Override public void onError(Throwable e) { display.show("error: " + e.getMessage()); } @Override public void onNext(Integer integer) { display.show("next: " + integer); } }; observable.subscribe(observer); .JAVA
  • 17.
    #dfua To subscribe. Thismeans creating Subscription. Subscription Subscription subscription = observable.subscribe(observer); ... if(!subscription.isUnsubscribed()) { subscription.unsubscribe(); } .JAVA
  • 18.
    #dfua To subscribe. Thismeans creating Subscription. In fact Subscription class is rarely used, but can be useful to unsubscribe when we don’t need to receive events Subscription Subscription subscription = observable.subscribe(observer); ... if(!subscription.isUnsubscribed()) { subscription.unsubscribe(); } .JAVA
  • 19.
    #dfua Looks more readable,isn’t it? At least takes one screen, not three :) Observable + Observer with lambdas rx.Observable<Integer> observable = rx.Observable.create(subscriber -> { for (int i = 0; i < N; i++) subscriber.onNext(random.nextInt(MAX)); subscriber.onCompleted(); }); observable.subscribe( integer -> display.show("next: " + integer), throwable -> display.show("error: " + throwable.getMessage()), () -> display.show("completed")); .JAVA
  • 20.
    #dfua Reactive Systems are: *CheckReactiveManifesto.org for detailed definitions: Message Driven Responsive Resilient Scalable (Elastic)
  • 21.
    From everything, ...evenfrom air :) Creating Observables
  • 22.
    #dfua Observable.from() ENTER FILENAME/LANG ArrayList<Integer> arrayList= new ArrayList<>(); int MAX_N = random.nextInt(12) + 5; for (int i = 0; i < MAX_N; i++) arrayList.add(random.nextInt(MAX)); rx.Observable.from(arrayList) .subscribe( integer -> display.show("next: " + integer), throwable -> display.show("error: " + throwable.getMessage()), () -> display.show("complete")); .JAVA
  • 23.
    #dfua Observable.just() ENTER FILENAME/LANG private List<Integer>generate() { Random r = new Random(); int n = r.nextInt(5) + 5; ArrayList<Integer> a = new ArrayList<>(); for (int i = 0; i < n; i++) a.add(r.nextInt(100)); return a; } public void just() { rx.Observable.just(generate()) .subscribe(integer -> display.show("next: " + integer), throwable -> display.show("error: " + throwable.getMessage()), () -> display.show("complete")); } .JAVA
  • 24.
    #dfua Observable.interval() Random r =new Random(); rx.Observable.interval(2, TimeUnit.SECONDS) .map(t -> new long[]{t, r.nextInt(100)}) .limit(5) .subscribe( tuple -> display.show("next: " + Arrays.toString(tuple)), throwable -> { }, () -> display.show("complete")); .JAVA
  • 25.
    #dfua Retrofit RestAdapter restAdapter =new RestAdapter.Builder() .setEndpoint("https://api.github.com") .build(); GitHubService service = restAdapter.create(GitHubService.class); // Retrofit can return observable which we handle as any other observable service.listRepos("c-mars") .flatMap(Observable::from) .limit(10) .subscribe(repo -> display.show("next: " + repo.toString()), throwable -> display.show("error: " + throwable.getMessage()), () -> display.show("completed")); .JAVA
  • 26.
    #dfua RxBindings Button button; ... RxView.clicks(button) .map(v ->++counter) .debounce(500, TimeUnit.MILLISECONDS) .subscribe(c -> display.show("button " + c)); .JAVA
  • 27.
  • 28.
    #dfua Blocking private final AmmeterReadings[]data = { new AmmeterReadings(1, 0.5), ... }; private static float getMaxValue(AmmeterReadings[] data) { return MathObservable.max(rx.Observable.from(data) .map(AmmeterReadings::getCurrent)) .toBlocking().firstOrDefault(0L); } .JAVA By default rx.Observable is async. But it can be converted to BlockingObservable and return result in-place, using functional computations.
  • 29.
    #dfua first, last, take,orDefault private final AmmeterReadings[] data = { new AmmeterReadings(1, 0.5), ... }; private static float getMaxValue(AmmeterReadings[] data) { return MathObservable.max(rx.Observable.from(data) .map(AmmeterReadings::getCurrent)) .toBlocking().firstOrDefault(0L); } .JAVA We can take first, last or any item from BlockingObservable. If it’s empty, we can define default value.
  • 30.
    #dfua take from Observable privatefinal AmmeterReadings[] data = { new AmmeterReadings(1, 0.5), ... }; private static float getMaxValue(AmmeterReadings[] data) { return MathObservable.max( rx.Observable.from(data) .map(AmmeterReadings::getCurrent) .takeLast(5) ) .toBlocking().firstOrDefault(0L); } .JAVA rx.Observable (non-blocking) provides method take() to take multiple items from stream.
  • 31.
    #dfua singleOrDefault rx.Observable.range(0, 0) .singleOrDefault(-1) .forEach(i ->getDisplay().show("single:" + i)); .JAVA Check whether rx.Observable contains only one event/item.
  • 32.
    #dfua defaultIfEmpty rx.Observable.range(0, max) .defaultIfEmpty(999) .forEach(i ->getDisplay().show("range 0->" + max + ", value (999 if empty):" + String.valueOf(i))); .JAVA Almost the same as singleOrDefault
  • 33.
    #dfua toIterable final Integer[] data= {200, 4, 145, -1, 10, -12, 80}; Iterable<Integer> iterable = rx.Observable.from(data) .toBlocking().toIterable(); for (Integer i : iterable) { display.show("iterable:" + i.toString()); } .JAVA BlockingObservable.toIterable() converts rx.Observable to collection
  • 34.
    #dfua forEach final Integer[] data= {200, 4, 145, -1, 10, -12, 80}; rx.Observable.from(data) .forEach(i -> display.show("iterable:" + i.toString())); .JAVA forEach() is just shorcut to .subscribe()
  • 35.
    #dfua takeUntil rx.Observable.range(0, 10) .takeUntil(i ->i == 5) .forEach(i -> getDisplay().show(String.valueOf(i))); // out: 0, 1, 2, 3, 4, 5 .JAVA Just a variant of take(), which completes when condition matches.
  • 36.
    #dfua contains rx.Observable.range(0, max) .contains(2) .forEach(i ->getDisplay().show("range: " + 0 + "->" + max + ",contains 2: " + String.valueOf(i))); // out: true (or false) .JAVA Check whether stream contains certain value
  • 37.
    #dfua filter rx.Observable.range(0, 10) .filter(i ->i > 5 && i < 9 ) .forEach(i -> getDisplay().show(i)); // out: 6, 7, 8 .JAVA Like takeUntil, just filter :)
  • 38.
    #dfua debounce long[] times ={3, 2, 1, 5, 2, 6}; rx.Observable<Pair<Integer, Long>> observable = rx.Observable.create(subscriber -> { int sz = times.length; for (int i = 0; i < sz; i++) { try { long t = times[i]; TimeUnit.MILLISECONDS.sleep(t); subscriber.onNext(new Pair<>(i, t)); } catch (InterruptedException e) { subscriber.onError(e); } } subscriber.onCompleted(); }); observable.debounce(4, TimeUnit.MILLISECONDS) .subscribe(pair -> getDisplay().show("out: value=" + pair.first + ", time=" + pair.second)); .JAVA
  • 39.
    #dfua sample long[] times ={3, 2, 1, 5, 4, 3, 1}; rx.Observable<Pair<Integer, Long>> observable = rx.Observable.create(subscriber -> { int sz = times.length; for (int i = 0; i < sz; i++) { try { long t = times[i]; TimeUnit.MILLISECONDS.sleep(t * 10); subscriber.onNext(new Pair<>(i, t)); } catch (InterruptedException e) { subscriber.onError(e); } } subscriber.onCompleted(); }); observable.sample(40, TimeUnit.MILLISECONDS) .subscribe(pair -> getDisplay().show("out: value=" + pair.first + "; time=" + pair.second)); .JAVA
  • 40.
  • 41.
    #dfua merge rx.Observable first =Observable.range(0, 5); //int[] rx.Observable second = Observable.from(new String[]{"one", "two", "three", "four", "five"}); //String[] rx.Observable.merge(first, second) .forEach(item -> getDisplay().show(item.toString())); .JAVA Merges items from separate rx.Observables to single stream
  • 42.
    #dfua zip rx.Observable<Integer> first =Observable.range(0, 5); //int[] rx.Observable<String> second = Observable.from(new String[]{"one", "two", "three", "four", "five"}); //String[] rx.Observable.zip(first, second, (i, s) -> new Pair(s, i)) .forEach(pair -> getDisplay().show(pair.toString())); .JAVA Merges items from separate rx.Observables to single stream using combining function.
  • 43.
  • 44.
    #dfua retry rx.Observable<Integer> canFail =rx.Observable.create(new Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { for (int i = 0; i < 6; i++) { switch (i) { case 3: if (!failedOnce) { failedOnce = true; subscriber.onError(new Error()); return; } break; case 5: subscriber.onError(new Throwable()); return; } subscriber.onNext(i); } subscriber.onCompleted(); } }); .JAVA
  • 45.
    #dfua retry canFail.retry((integer, throwable) ->{ boolean retry = (throwable instanceof Error); getDisplay().show("retry, errors: " + integer); return retry; }) .subscribe(i -> { getDisplay().show(i); }, throwable -> { getDisplay().show("error: " + throwable.getMessage()); }); .JAVA
  • 46.
    #dfua retry In case oferror we can check condition in retry() and then re-subscribe and try once more
  • 47.
  • 48.
    #dfua MathObservable private final AmmeterReadings[]data = { new AmmeterReadings(1, 0.5), ... }; private static float getMaxValue(AmmeterReadings[] data) { return MathObservable.max(rx.Observable.from(data) .map(AmmeterReadings::getCurrent)) .toBlocking().firstOrDefault(0L); } .JAVA Plugin MathObservable: compile 'io.reactivex:rxjava-math:1.0.0' max, average, sum, count
  • 49.
    #dfua Average rx.Observable<Integer> integers =rx.Observable.range(0, 10); MathObservable.averageInteger(integers).subscribe(avg -> { getDisplay().show(avg); }); .JAVA Many methods of MathObservable has type-aware alternatives
  • 50.
    #dfua reduce rx.Observable.range(0, 10).reduce((a, b)-> { int c = a + b; getDisplay().show("reduce: a=" + a + " + " + b + " = " + c); return c; }).forEach(value -> getDisplay().show("result: " + value)); .JAVA Classic reduce operation, common for all functional programming languages
  • 51.
    Ubiquitous mediums thatlike actors can play any role RxJava Subjects
  • 52.
    #dfua Creating Subjects PublishSubject<String> subject= PublishSubject.create(); example(subject); … ReplaySubject<String> subject = ReplaySubject.createWithSize(2); example(subject); .JAVA Subjects have method .create() for this. ReplaySubject can also be created with predefined number of events to replay on subscription.
  • 53.
    #dfua Example code private voidexample(Subject<String, String> subject) { subject.onNext("before 1"); subject.onNext("before 2"); subject.onNext("before 3"); subject.onNext("before 4"); subject.subscribe(s -> getDisplay().show("subscribed: " + s)); subject.onNext("after 5"); subject.onNext("after 6"); subject.onNext("after 7"); subject.onNext("after 8"); subject.onCompleted(); } .JAVA Subject can act both like Observable and Observer. So we can call .onNext, .onComplete manually and trigger subscription callbacks
  • 54.
    #dfua Subjects behaviour PublishSubject Is justa proxy for events AsyncSubject Replays only last event onComplete ReplaySubject Replays last N events and then proxies the same as Publish BehaviorSubject Replays only last event and then proxies the same as Publish
  • 55.
    #dfua ReactiveX Diagrams In ahour of despair - seek inspiration at ReactiveX.io
  • 56.
  • 57.
    #dfua Schedulers rx.Observable.from(readFromFile(context)) .subscribeOn(Schedulers.io()) .forEach(line -> textView.append("n"+ line)); .JAVA By default rx.Observable is single-threaded. Here come Schedulers to hide threading and synchronization behind the functional interface. Just call .subscribeOn() and define which kind of threading you want
  • 58.
    #dfua Schedulers rx.Observable source =rx.Observable.range(0, 10).map(integer -> { List<Integer> outs = new ArrayList<>(); for (int i = 0; i < 1000; i++) { for (int j = 0; j < 1000; j++) { outs.add((int) Math.pow(i, j)); } } return outs; }).flatMap(Observable::from); MathObservable.sumInteger(source) .subscribeOn(Schedulers.computation()) .subscribe(integer -> textView.setText("final sum: " + integer.toString())); .JAVA
  • 59.
    #dfua Android UI MathObservable.sumInteger(source) .subscribeOn(Schedulers.computation()) .subscribe(integer ->textView.setText("final sum: " + integer.toString())); .JAVA Scheduler move execution to another appropriate thread. But when we try to update UI from this chain - something bad happens...
  • 60.
    #dfua Android UI MathObservable.sumInteger(source) .subscribeOn(Schedulers.computation()) .subscribe(integer ->textView.setText("final sum: " + integer.toString())); .JAVA Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. E/AndroidRuntime: at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556) E/AndroidRuntime: at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:942) E/AndroidRuntime: at android.view.ViewGroup.invalidateChild(ViewGroup.java:5081) E/AndroidRuntime: at android.view.View.invalidateInternal(View.java:12713) E/AndroidRuntime: at android.view.View.invalidate(View.java:12677) E/AndroidRuntime: at android.view.View.invalidate(View.java:12661) ... CONSOLE
  • 61.
  • 62.
  • 63.
    #dfua AndroidSchedulers rx.Observable.from(readFromFile(context)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .forEach(line -> textView.append("n"+ line)); .JAVA .subscribeOn defines thread on which computations run, .observeOn defines thread on which rx.Observer callbacks will run
  • 64.
    #dfua Activity Lifecycle // Activity privateSubscription subscription; protected void onCreate(Bundle savedInstanceState) { this.subscription = observable.subscribe(this); } ... protected void onDestroy() { this.subscription.unsubscribe(); super.onDestroy(); } .JAVA Use subscription or CompositeSubscription
  • 65.
  • 66.
    #dfua Where to look? ●JavaDoc: http://reactivex.io/RxJava/javadoc/rx/Observable.html ● List of Additional Reading from RxJava Wiki: https://github.com/ReactiveX/RxJava/wiki/Additional-Reading ● RxJava Essentials by Ivan Morgillo: https://www.packtpub.com/application-development/rxjava-essentials ● RxMarbles - interactive diagrams: http://rxmarbles.com/
  • 67.
  • 68.