RxJava in practice
-
Upload
javier-gamarra -
Category
Technology
-
view
558 -
download
0
Transcript of RxJava in practice
MADRID · NOV 27-28 · 2015
RxJava in practiceJavier Gamarra
MADRID · NOV 27-28 · 2015
http://kcy.me/29crj (slides)&
http://kcy.me/296bu (commits)
MADRID · NOV 27-28 · 2015
Environment
Eclipse | Android Studio (RxAndroid)
RxJava.jar
[Java 8] || [Retrolambda] :P
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
MADRID · NOV 27-28 · 2015
Github
● http://kcy.me/296bu● koans● código● commit a commit● Podéis preguntarme en cualquier
momento
MADRID · NOV 27-28 · 2015
Who?
Javier Gamarra / @nhpatt
@liferay
@cyliconvalley / @agilespain
MADRID · NOV 27-28 · 2015
Ask!
Please? Pretty please? Please pretty please with sugar on top?
MADRID · NOV 27-28 · 2015
Background?
MADRID · NOV 27-28 · 2015
Why?
MADRID · NOV 27-28 · 2015
Why? (in java)
multithreading is hard
futures are complicated
callbacks are hell
MADRID · NOV 27-28 · 2015
Rx comes to the rescue!
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
MADRID · NOV 27-28 · 2015
a library
MADRID · NOV 27-28 · 2015
A library?
Extensions to .NET framework
Netflix
MADRID · NOV 27-28 · 2015
Libraries are tools
If all you have is a hammer, everything looks like a nail
MADRID · NOV 27-28 · 2015
a library to modelObservables & Subscribers
MADRID · NOV 27-28 · 2015
Observables and Subscribers
An Observable emits items.
A Subscriber consumes those items.
MADRID · NOV 27-28 · 2015Observer pattern?
MADRID · NOV 27-28 · 2015
My very first observableObservable<String> myObs = Observable. create(new Observable.
OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext( "Hi!");
subscriber.onCompleted();
}
});
MADRID · NOV 27-28 · 2015
My very first subscriberSubscriber<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);
}
};
MADRID · NOV 27-28 · 2015
My very first subscription
myObs.subscribe(mySubs);
MADRID · NOV 27-28 · 2015
A bit verbose...
Let’s simplify with Java8 and RxJava
● lamdbas● Observable.just● .subscribe()
MADRID · NOV 27-28 · 2015
That’s better...
Observable.just("Hi!").subscribe(System.out::println);
MADRID · NOV 27-28 · 2015
Why?
More than the observer pattern
● Observables only emit when someone listening
● OnFinished● OnError
MADRID · NOV 27-28 · 2015
Let’s use those differences
subscribe admits 3 parameters
● OnNext● OnFinished● OnError
MADRID · NOV 27-28 · 2015
You said “items”
Observable.from admits a list of elements
MADRID · NOV 27-28 · 2015
Ok, let’s recap…
Iterators?
MADRID · NOV 27-28 · 2015
Iterators?
● Iterators are pull and synchronous
● Subscribers are push and asynchronous
MADRID · NOV 27-28 · 2015
to represent any operation as an “asynchronous data stream”
MADRID · NOV 27-28 · 2015
Everything is a stream
MADRID · NOV 27-28 · 2015
Everything is a streamWe can model everything as a
stream
MADRID · NOV 27-28 · 2015
Everything is a stream
A network call is also a stream
Like using retrofit with this API
MADRID · NOV 27-28 · 2015
“declaratively composed”
MADRID · NOV 27-28 · 2015
Operators
MADRID · NOV 27-28 · 2015
Operators
Transform a stream
rxmarbles and android app
MADRID · NOV 27-28 · 2015
Operators
Map
MADRID · NOV 27-28 · 2015
Map
List<String> severalThings = Arrays.asList("1", "2");
Observable.from(severalThings) .map((s) -> “Element “ + s) .subscribe(System.out::println);
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);
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
MADRID · NOV 27-28 · 2015
Flatmap
Flatmap
Obs -> elements
MADRID · NOV 27-28 · 2015
Flatmap
service.listRepos("nhpatt") .flatMap(Observable::from) .map(Repo::getName) .map((s) -> s.replace("-", " ")) .subscribe(System.out::println);
MADRID · NOV 27-28 · 2015
Flatmap
Concatmap -> ordered flatmap
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);
MADRID · NOV 27-28 · 2015
Scan & old codeservice.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);
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;
MADRID · NOV 27-28 · 2015
Operators
● merge● flatMap● zip
Nice things™ : parallel jobs!
MADRID · NOV 27-28 · 2015
Zipping requestsObservable<Repo> repo = service.listRepos("nhpatt") .flatMap(Observable::from) .take(1);
Observable<Commit> commit = service.listCommits("nhpatt", "Android") .flatMap(Observable::from) .take(1);
Observable.zip(repo, commit, this::updateCommit).subscribe(repo1 -> { System.out.println(repo1.getCommit().getUrl());});
MADRID · NOV 27-28 · 2015
Operators
Amazing documentation● Async● Blocking● Combining● Conditional● Error handling● Filtering● Mathematical● Creation● String● Transforming● Utility
MADRID · NOV 27-28 · 2015
Subscribers are asynchronous?
No, not really
MADRID · NOV 27-28 · 2015
“on any thread”
MADRID · NOV 27-28 · 2015
Schedulers!
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 ...
MADRID · NOV 27-28 · 2015
Schedulers
.subscribeOn(Schedulers...)
.observeOn(Schedulers...)● io● computation● newThread● trampoline● test
MADRID · NOV 27-28 · 2015
Schedulers
service.listRepos("nhpatt") .subscribeOn(Schedulers.immediate()) .observeOn(Schedulers.immediate()) .subscribe(System.out::println);
MADRID · NOV 27-28 · 2015
Schedulers
RxJava operators have default threads
Interval?
MADRID · NOV 27-28 · 2015
Use cases?
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
MADRID · NOV 27-28 · 2015
Android?
MADRID · NOV 27-28 · 2015
Why?
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
MADRID · NOV 27-28 · 2015
How RxAndroid helps?
MADRID · NOV 27-28 · 2015
Android schedulersservice.listRepos("nhpatt") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(newRepos -> { repos.addAll(newRepos); adapter.notifyDataSetChanged(); });
MADRID · NOV 27-28 · 2015
Orientation Problem
Orientation Problem
● onCreate gets called again● state is lost
MADRID · NOV 27-28 · 2015
Orientation Problem
Programmer’s job:
● Store/Restore state● Restore view● Call again the user task? ● Wait until it finishes?
MADRID · NOV 27-28 · 2015
How RxAndroid helps?
MADRID · NOV 27-28 · 2015
Orientation Problem
Observable is easy to persist (retain | singleton)
Observable can continue (cache and retry)
RxLifecycle
MADRID · NOV 27-28 · 2015
Orientation Problem
Observable<List<Repo>> github = RetrofitService.getGithub()
.listRepos("nhpatt")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.cache();
MADRID · NOV 27-28 · 2015
More Android
Lifecycle (RxLifecyle)
Views (RxBinding)
MADRID · NOV 27-28 · 2015
But...
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
MADRID · NOV 27-28 · 2015
Easy to unsubscribe@Overrideprotected void onStop() { super.onStop();
subscription.unsubscribe();}
.isUnsubscribed() :(
MADRID · NOV 27-28 · 2015
Let’s recap
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
MADRID · NOV 27-28 · 2015
a library to represent any operation as an
observable on any thread,
declaratively composed, and consumed by multiple objects
MADRID · NOV 27-28 · 2015
a library to represent any operation as an
observable with schedulers
declaratively composed, and consumed by multiple objects
MADRID · NOV 27-28 · 2015
a library to represent any operation as an
observable with schedulersand operators
and consumed by multiple objects
MADRID · NOV 27-28 · 2015
a library to represent any operation as an
observable with schedulersand operators
listened by subscribers
MADRID · NOV 27-28 · 2015
But...
MADRID · NOV 27-28 · 2015
But...
● Learning curve
● Hard to debug (Frodo library)
● Backpressure
MADRID · NOV 27-28 · 2015
Questions?
MADRID · NOV 27-28 · 2015
Where to know more...
● reactivex.io (amazing docs)
● RxJava wiki
● Dan Lew
● Use cases
MADRID · NOV 27-28 · 2015
Where to know more...
nhpatt (twitter | github | email | slack)
I’ll do anything for good votes
MADRID · NOV 27-28 · 2015
Feedback
Click here :P
MADRID · NOV 27-28 · 2015
RxJava in practiceJavier Gamarra
MADRID · NOV 27-28 · 2015
Other interesting operators...
MADRID · NOV 27-28 · 2015
Takeservice.listRepos("nhpatt") .flatMap(Observable::from) .map(Repo::getName) .map((s) -> s.replace("-", " ")) .filter((s) -> s.startsWith("Android")) .take(2) .subscribe(System.out::println);
MADRID · NOV 27-28 · 2015
Operators
distinctUntilChanged
compose
MADRID · NOV 27-28 · 2015
Errors?
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
MADRID · NOV 27-28 · 2015
Errors
And we can customize the flow: onErrorResumeNext onErrorReturn retry ...
MADRID · NOV 27-28 · 2015
Why this is useful?
MADRID · NOV 27-28 · 2015
Why this is useful?
Observables and subscribers can do anything
MADRID · NOV 27-28 · 2015
Why this is useful?
Observable a database query
Subscriber displaying results on the screen
MADRID · NOV 27-28 · 2015
Why this is useful?
Observable a click on the screen
Subscriber reacting to it
MADRID · NOV 27-28 · 2015
Why this is useful?
Observable a stream of bytes from the internet
Subscriber write them to disk
MADRID · NOV 27-28 · 2015
Why this is useful?
Observable and Subscriber are independent of the transformations
MADRID · NOV 27-28 · 2015
Why this is useful?
I can compose/chain any map/filter calls I want
Only matters the return type
MADRID · NOV 27-28 · 2015
Side effects?
MADRID · NOV 27-28 · 2015
Side effects
doOn methods:
● doOnNext() for debugging
● doOnError() for error handling
● doOnNext() to save/cache results
MADRID · NOV 27-28 · 2015
Side effectsObservable 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));
MADRID · NOV 27-28 · 2015
Side effectsflatMap(id -> service.get()
.doOnError(t -> {// report problem to UI
}).onErrorResumeNext(Observable.empty()))
MADRID · NOV 27-28 · 2015
Cold & Hot
MADRID · NOV 27-28 · 2015
Cold & Hot
Observables only emit when someone listening?
Cold observables only emit when subscribed
But hot observables emit instantly
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()
MADRID · NOV 27-28 · 2015
Cold & Hot
publish & connect?
“like transactions”
Assume everything is cold
MADRID · NOV 27-28 · 2015
Testing?
MADRID · NOV 27-28 · 2015
More cool things?
● testscheduler
● toIterator()
● Obs.error(), Obs.empty()
MADRID · NOV 27-28 · 2015
Subjects
MADRID · NOV 27-28 · 2015
Subjects
Both observable & observer
MADRID · NOV 27-28 · 2015
Subjects
AsyncSubject -> takeLast(1)
PublishSubject -> publish()
ReplaySubject -> replay()/cache()
BehaviorSubject -> replay(1)/cache(1)
MADRID · NOV 27-28 · 2015
RxJava in practiceJavier Gamarra