Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
RxJava in practice
Search
Javier Gamarra
November 30, 2015
Programming
1
300
RxJava in practice
Slides for a workshop about RxJava & RxAndroid delivered at the Codemotion 2015.
Javier Gamarra
November 30, 2015
Tweet
Share
More Decks by Javier Gamarra
See All by Javier Gamarra
2000 katas later @cylicon
nhpatt
0
96
2000 katas later @CAS15
nhpatt
0
83
Métricas: lo bueno, lo feo y lo malo
nhpatt
0
150
Working Effectively with Legacy Code
nhpatt
0
340
Performance myths in android
nhpatt
2
230
How *not* to design an SDK
nhpatt
0
41
Angular2 @SC Toledo
nhpatt
0
47
Cambiar una empresa con juegos ágiles
nhpatt
0
230
Android M
nhpatt
0
54
Other Decks in Programming
See All in Programming
StoreKit2によるiOSのアプリ内課金のリニューアル
kangnux
0
110
Ruby Pattern Matching
bkuhlmann
0
920
Komplexe Oberflächen mit SVG und der Web Animation API
joergneumann
0
670
Compose-View Interop in Practice (mDevCamp 2024)
stewemetal
0
120
スキーマ駆動開発による品質とスピードの両立 - 私達は何故、スキーマを書くのか
kentaroutakeda
0
160
Code Reviews
bkuhlmann
4
890
GitHub Actionsで泣かないためにやっておきたい設定 / Recommended GHA settings to avoid crying
pinkumohikan
3
530
はてなにおける CSS Modules、及び CSS Modules に足りないもの / CSS Modules in Hatena, and CSS Modules missing parts
mizdra
6
910
Rubyでたのしむクリエイティブコーディング/Enjoy Creative coding with Ruby
chobishiba
1
170
Milestoner
bkuhlmann
1
410
try! Swift Tokyo 2024 参加報告 / try! Swift Tokyo 2024 Report
hironytic
0
200
PHPはいつから死んでいるかの調査
chiroruxx
1
380
Featured
See All Featured
The Pragmatic Product Professional
lauravandoore
25
5.8k
Optimising Largest Contentful Paint
csswizardry
8
2.4k
Put a Button on it: Removing Barriers to Going Fast.
kastner
58
3k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
6
1.5k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
7
990
Side Projects
sachag
451
41k
Scaling GitHub
holman
457
140k
Build your cross-platform service in a week with App Engine
jlugia
225
17k
The Brand Is Dead. Long Live the Brand.
mthomps
49
28k
Design by the Numbers
sachag
274
18k
How to Ace a Technical Interview
jacobian
272
22k
GitHub's CSS Performance
jonrohan
1025
450k
Transcript
MADRID · NOV 27-28 · 2015 RxJava in practice Javier
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 model
Observables & Subscribers
MADRID · NOV 27-28 · 2015 Observables and Subscribers An
Observable emits items. A Subscriber consumes those items.
MADRID · NOV 27-28 · 2015 Observer pattern?
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(); } });
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); } };
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 stream
We 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 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);
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 requests Observable<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 schedulers service.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 @Override
protected 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 schedulers and operators and consumed by multiple objects
MADRID · NOV 27-28 · 2015 a library to represent
any operation as an observable with schedulers and 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 practice Javier
Gamarra
MADRID · NOV 27-28 · 2015 Other interesting operators...
MADRID · NOV 27-28 · 2015 Take service.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 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) );
MADRID · NOV 27-28 · 2015 Side effects flatMap(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 practice Javier
Gamarra