Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
RxJava in practice
1. MADRID · NOV 27-28 · 2015
RxJava in practice
Javier Gamarra
2. MADRID · NOV 27-28 · 2015
http://kcy.me/29crj (slides)
&
http://kcy.me/296bu (commits)
3. MADRID · NOV 27-28 · 2015
Environment
Eclipse | Android Studio (RxAndroid)
RxJava.jar
[Java 8] || [Retrolambda] :P
4. MADRID · NOV 27-28 · 2015
Environment
Android Studio:
compile 'io.reactivex:rxandroid:1.0.1'
compile 'io.reactivex:rxjava:1.0.16'
Eclipse:
● Copy jars to lib/ and add jar in project
5. MADRID · NOV 27-28 · 2015
Github
● http://kcy.me/296bu
● koans
● código
● commit a commit
● Podéis preguntarme en cualquier
momento
6. MADRID · NOV 27-28 · 2015
Who?
Javier Gamarra / @nhpatt
@liferay
@cyliconvalley / @agilespain
7. MADRID · NOV 27-28 · 2015
Ask!
Please? Pretty please? Please pretty please with sugar on top?
10. MADRID · NOV 27-28 · 2015
Why? (in java)
multithreading is hard
futures are complicated
callbacks are hell
11. MADRID · NOV 27-28 · 2015
Rx comes to the rescue!
12. MADRID · NOV 27-28 · 2015
a library
to represent any operation as an
asynchronous data stream
on any thread,
declaratively composed,
and consumed by multiple objects
19. MADRID · NOV 27-28 · 2015
My very first observable
Observable<String> myObs = Observable. create(new Observable.
OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext( "Hi!");
subscriber.onCompleted();
}
});
20. MADRID · NOV 27-28 · 2015
My very first subscriber
Subscriber<String> mySubs = new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onNext(String s) {
System. out.println(s);
}
};
21. MADRID · NOV 27-28 · 2015
My very first subscription
myObs.subscribe(mySubs);
22. MADRID · NOV 27-28 · 2015
A bit verbose...
Let’s simplify with Java8 and RxJava
● lamdbas
● Observable.just
● .subscribe()
23. MADRID · NOV 27-28 · 2015
That’s better...
Observable
.just("Hi!")
.subscribe(System.out::println);
24. MADRID · NOV 27-28 · 2015
Why?
More than the observer pattern
● Observables only emit when someone
listening
● OnFinished
● OnError
25. MADRID · NOV 27-28 · 2015
Let’s use those differences
subscribe admits 3 parameters
● OnNext
● OnFinished
● OnError
26. MADRID · NOV 27-28 · 2015
You said “items”
Observable.from admits a list of elements
27. MADRID · NOV 27-28 · 2015
Ok, let’s recap…
Iterators?
28. MADRID · NOV 27-28 · 2015
Iterators?
● Iterators are pull and synchronous
● Subscribers are push and asynchronous
29. MADRID · NOV 27-28 · 2015
to represent any operation as an
“asynchronous data stream”
30. MADRID · NOV 27-28 · 2015
Everything is a stream
31. MADRID · NOV 27-28 · 2015
Everything is a stream
We can model everything as a
stream
32. MADRID · NOV 27-28 · 2015
Everything is a stream
A network call is also a stream
Like using retrofit with this API
33. MADRID · NOV 27-28 · 2015
“declaratively composed”
38. MADRID · NOV 27-28 · 2015
Map
We can return another type:
List<String> severalThings = Arrays.asList("1", "2");
Observable.from(severalThings)
.map(Integer::valueOf)
.subscribe(System.out::println);
39. MADRID · NOV 27-28 · 2015
Map
Let’s do the same with our repos…
And… I can’t because we return a List
And using Observable.from… NOP
40. MADRID · NOV 27-28 · 2015
Flatmap
Flatmap
Obs -> elements
41. MADRID · NOV 27-28 · 2015
Flatmap
service.listRepos("nhpatt")
.flatMap(Observable::from)
.map(Repo::getName)
.map((s) -> s.replace("-", " "))
.subscribe(System.out::println);
42. MADRID · NOV 27-28 · 2015
Flatmap
Concatmap -> ordered flatmap
43. MADRID · NOV 27-28 · 2015
Filter
service.listRepos("nhpatt")
.flatMap(Observable::from)
.map(Repo::getName)
.map((s) -> s.replace("-", " "))
.filter((s) -> s.startsWith("Android"))
.subscribe(System.out::println);
44. MADRID · NOV 27-28 · 2015
Scan & old code
service.listRepos("nhpatt")
.flatMap(Observable::from)
.map(Repo::getName)
.map((s) -> s.replace("-", " "))
.filter((s) -> s.startsWith("Android"))
.take(2)
.map(String::length)
.scan((x, y) -> x * y)
.subscribe(System.out::println);
45. MADRID · NOV 27-28 · 2015
Scan & old code
(l) -> {
int result = 0;
int i = 0;
int oldLength = 1;
for (Repo repo : l) {
String name = repo.getName();
String replacedName = name.replace( "-", " ");
if (replacedName.startsWith( "Android") && i < 2) {
result = replacedName.length() * oldLength;
oldLength = result;
System.out.println(result);
i++;
}
}
return result;
46. MADRID · NOV 27-28 · 2015
Operators
● merge
● flatMap
● zip
Nice things™ : parallel jobs!
52. MADRID · NOV 27-28 · 2015
Schedulers
I define an API declaratively
and later in the implementation run it:
asynchronously
or in a separate Thread
or in a Threadpool
or synchronously
...
53. MADRID · NOV 27-28 · 2015
Schedulers
.subscribeOn(Schedulers...)
.observeOn(Schedulers...)
● io
● computation
● newThread
● trampoline
● test
54. MADRID · NOV 27-28 · 2015
Schedulers
service.listRepos("nhpatt")
.subscribeOn(Schedulers.immediate())
.observeOn(Schedulers.immediate())
.subscribe(System.out::println);
55. MADRID · NOV 27-28 · 2015
Schedulers
RxJava operators have default threads
Interval?
57. MADRID · NOV 27-28 · 2015
Use cases
● Autocomplete with debounce | sample…
● Accumulate calls with buffer...
● Polling with timeout | window…
● Form Validation with combineLatest…
● Retrieve data fast from cache | network call with
concat | merge…
● Button click with delay, listen on other thread
60. MADRID · NOV 27-28 · 2015
Why? (in android)
Main/UI thread and background problem
● Can’t do heavy tasks on UI
● Can’t update view on background
● AsyncTasks are bad
● Handlers can leak
62. MADRID · NOV 27-28 · 2015
Android schedulers
service.listRepos("nhpatt")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(newRepos -> {
repos.addAll(newRepos);
adapter.notifyDataSetChanged();
});
63. MADRID · NOV 27-28 · 2015
Orientation Problem
Orientation Problem
● onCreate gets called again
● state is lost
64. MADRID · NOV 27-28 · 2015
Orientation Problem
Programmer’s job:
● Store/Restore state
● Restore view
● Call again the user task?
● Wait until it finishes?
66. MADRID · NOV 27-28 · 2015
Orientation Problem
Observable is easy to persist
(retain | singleton)
Observable can continue (cache and retry)
RxLifecycle
67. MADRID · NOV 27-28 · 2015
Orientation Problem
Observable<List<Repo>> github = RetrofitService.
getGithub()
.listRepos("nhpatt")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.cache();
68. MADRID · NOV 27-28 · 2015
More Android
Lifecycle (RxLifecyle)
Views (RxBinding)
70. MADRID · NOV 27-28 · 2015
But...
Subscriptions leak memory :’(
We have to call to unsubscribe
(CompositeSubscription helps)
And don’t include references to the
object/activity
71. MADRID · NOV 27-28 · 2015
Easy to unsubscribe
@Override
protected void onStop() {
super.onStop();
subscription.unsubscribe();
}
.isUnsubscribed() :(
73. MADRID · NOV 27-28 · 2015
a library
to represent any operation as an
asynchronous data stream
on any thread,
declaratively composed,
and consumed by multiple objects
74. MADRID · NOV 27-28 · 2015
a library
to represent any operation as an
observable
on any thread,
declaratively composed,
and consumed by multiple objects
75. MADRID · NOV 27-28 · 2015
a library
to represent any operation as an
observable
with schedulers
declaratively composed,
and consumed by multiple objects
76. MADRID · NOV 27-28 · 2015
a library
to represent any operation as an
observable
with schedulers
and operators
and consumed by multiple objects
77. MADRID · NOV 27-28 · 2015
a library
to represent any operation as an
observable
with schedulers
and operators
listened by subscribers
89. MADRID · NOV 27-28 · 2015
onError() is called if an Exception is thrown at
any time (this is cool)
The operators don't have to handle the
Exception
No more callbacks
Errors
90. MADRID · NOV 27-28 · 2015
Errors
And we can customize the flow:
onErrorResumeNext
onErrorReturn
retry
...
99. MADRID · NOV 27-28 · 2015
Side effects
doOn methods:
● doOnNext() for debugging
● doOnError() for error handling
● doOnNext() to save/cache results
100. MADRID · NOV 27-28 · 2015
Side effects
Observable someObservable = Observable
.from(Arrays.asList(new Integer[]{2, 7, 11}))
.doOnNext(System.out::println)
.filter(prime -> prime % 2 == 0)
.doOnNext(System.out::println)
.count()
.doOnNext(System.out::println)
.map(
number -> String.format(“Contains %d
elements”, number)
);
101. MADRID · NOV 27-28 · 2015
Side effects
flatMap(id -> service.get()
.doOnError(t -> {
// report problem to UI
})
.onErrorResumeNext(Observable.empty()))
103. MADRID · NOV 27-28 · 2015
Cold & Hot
Observables only emit when someone
listening?
Cold observables only emit when subscribed
But hot observables emit instantly
104. MADRID · NOV 27-28 · 2015
Cold & Hot
You can convert between both states
● “Hot -> cold” using defer() or merge(),
zip()...
● “Cold -> Hot” using publish() & connect()
105. MADRID · NOV 27-28 · 2015
Cold & Hot
publish & connect?
“like transactions”
Assume everything is cold