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
ReactiveX in Android
Search
Richard Cirerol
March 19, 2016
Programming
0
58
ReactiveX in Android
An introduction to RxJava and RxAndroid (v1) and Rx patterns
Richard Cirerol
March 19, 2016
Tweet
Share
More Decks by Richard Cirerol
See All by Richard Cirerol
Unconventional Android - Dependency Injection with Dagger
codeprogression
0
100
Introduction to Kotlin, Pt. 1
codeprogression
0
110
Android Studio Tips
codeprogression
0
92
Android: Testing Reactive MVP Applications
codeprogression
0
160
Unconventional Android v3
codeprogression
0
33
Unconventional Android v2
codeprogression
3
410
A Brief History of the Internet
codeprogression
1
440
Other Decks in Programming
See All in Programming
Jakarta EE meets AI
ivargrimstad
0
730
Amazon Qを使ってIaCを触ろう!
maruto
0
420
「今のプロジェクトいろいろ大変なんですよ、app/services とかもあって……」/After Kaigi on Rails 2024 LT Night
junk0612
5
2.2k
レガシーシステムにどう立ち向かうか 複雑さと理想と現実/vs-legacy
suzukihoge
14
2.3k
cmp.Or に感動した
otakakot
3
230
デザインパターンで理解するLLMエージェントの作り方 / How to develop an LLM agent using agentic design patterns
rkaga
3
370
TypeScriptでライブラリとの依存を限定的にする方法
tutinoko
3
710
Hotwire or React? ~アフタートーク・本編に含めなかった話~ / Hotwire or React? after talk
harunatsujita
1
120
Vapor Revolution
kazupon
1
180
リアーキテクチャxDDD 1年間の取り組みと進化
hsawaji
1
220
Jakarta EE meets AI
ivargrimstad
0
670
Remix on Hono on Cloudflare Workers
yusukebe
1
300
Featured
See All Featured
Become a Pro
speakerdeck
PRO
25
5k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
1.9k
Fashionably flexible responsive web design (full day workshop)
malarkey
405
65k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
720
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
506
140k
Building Better People: How to give real-time feedback that sticks.
wjessup
364
19k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5k
Site-Speed That Sticks
csswizardry
0
33
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
0
110
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
93
16k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
26
2.1k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
6
430
Transcript
RxAndroid Using ReactiveX in Android RxAndroid | Richard Cirerol |
@codeprogression
Who am I? RxAndroid | Richard Cirerol | @codeprogression
Richard Cirerol @codeprogression http://codeprogression.com RxAndroid | Richard Cirerol | @codeprogression
Sr. Android Engineer at MLBAM RxAndroid | Richard Cirerol |
@codeprogression
RxAndroid | Richard Cirerol | @codeprogression
http://bit.ly/mlbam-theverge RxAndroid | Richard Cirerol | @codeprogression
What is ReactiveX? - http://reactivex.io RxAndroid | Richard Cirerol |
@codeprogression
The Observer pattern done right 4 Observer pattern 4 Iterator
pattern 4 Functional programming 4 Asynchronous RxAndroid | Richard Cirerol | @codeprogression
Reactive extensions originated in .NET (circa 2010) RxAndroid | Richard
Cirerol | @codeprogression
RxJava is a port of Rx.NET started by Netflix (circa
2013) RxAndroid | Richard Cirerol | @codeprogression
Languages - Java: RxJava - JavaScript: RxJS - C#: Rx.NET
- C#(Unity): UniRx - Scala: RxScala - Clojure: RxClojure - C++: RxCpp - Ruby: Rx.rb - Python: RxPY - Groovy: RxGroovy - JRuby: RxJRuby - Kotlin: RxKotlin - Swift: RxSwift ReactiveX for platforms and frameworks - RxNetty - RxAndroid - RxCocoa RxAndroid | Richard Cirerol | @codeprogression
RxJava = Observables + Operators + Schedulers RxAndroid | Richard
Cirerol | @codeprogression
RxAndroid = RxJava + Additional Schedulers RxAndroid | Richard Cirerol
| @codeprogression
RxJava = Observables + Operators + Schedulers RxAndroid | Richard
Cirerol | @codeprogression
Observable 4 Emits a stream of items to observers 4
Notifies observers of termination events 4 Error 4 Completed RxAndroid | Richard Cirerol | @codeprogression
Observable.just(0); RxAndroid | Richard Cirerol | @codeprogression
Observable.just(0); Observable.just(0, 1, 2); RxAndroid | Richard Cirerol | @codeprogression
// 5, 6, 7, 8, 9 Observable.range(5,5) RxAndroid | Richard
Cirerol | @codeprogression
Integer[] items = new Integer[]{ 2, 4, 6, 8, 10
} Observable.from(items); RxAndroid | Richard Cirerol | @codeprogression
Observable.create(new OnSubscribe<Integer>() @Override public void call(Observer Observer){} try{ for (int
i = 0; i < 5; i++){ observer.onNext(i); } observer.onCompleted() } catch(Exception e){ observer.onError(e); } } }); RxAndroid | Richard Cirerol | @codeprogression
----------------------------> RxAndroid | Richard Cirerol | @codeprogression
----1-----------------------> RxAndroid | Richard Cirerol | @codeprogression
----1----20-----------------> RxAndroid | Richard Cirerol | @codeprogression
----1----20---17------------> RxAndroid | Richard Cirerol | @codeprogression
----1----20---17---8--------> RxAndroid | Richard Cirerol | @codeprogression
----1----20---17---8----|---> RxAndroid | Richard Cirerol | @codeprogression
----1----20---17---8----X---> RxAndroid | Richard Cirerol | @codeprogression
Observer 4 Subscribes to an Observable 4 Reacts to emitted
items 4 Reacts to termination events RxAndroid | Richard Cirerol | @codeprogression
public interface Observer<T> { void onNext(T item); void onError(Throwable t);
void onCompleted(); } RxAndroid | Richard Cirerol | @codeprogression
Single-threaded? Multi-threaded? RxAndroid | Richard Cirerol | @codeprogression
Synchronous? Asynchronous? RxAndroid | Richard Cirerol | @codeprogression
From a DB? A web service? A singleton? RxAndroid |
Richard Cirerol | @codeprogression
Who cares? RxAndroid | Richard Cirerol | @codeprogression
Observer to Observable: Just tell me when you've got something
new And tell me when you're done RxAndroid | Richard Cirerol | @codeprogression
Listener vs. Observable RxAndroid | Richard Cirerol | @codeprogression
Listener 4 Registration managed by the parent of the target
4 Callback interfaces are custom per implementation RxAndroid | Richard Cirerol | @codeprogression
// Before calling... service.getFoo(); // First call one of... service.setListener(this);
service.addListener(this); // And implement... public interface Listener { void onFooChanged(Foo foo); } // And remember to clean up... service.setListener(null); service.removeListener(this); RxAndroid | Richard Cirerol | @codeprogression
Observables 4 Registration managed internally by the Observable 4 Subscription
interface is consistent RxAndroid | Richard Cirerol | @codeprogression
// A Subscriber is a subclass of Observer Subscription subscription
= service.getFoo() .subscribe(new Subscriber<Foo>(){ @Override public void onNext(Foo item){ doSomething(item); } @Override public void onError(Throwable e){ Log.e(e); } @Override public void onCompleted(){ hideProgress(); } }); RxAndroid | Richard Cirerol | @codeprogression
Subscription subscription = service.getFoo() .subscribe(new Action1<Foo>(){ @Override public void call(Foo
foo){ doSomething(foo)); } }); RxAndroid | Richard Cirerol | @codeprogression
Subscription subscription = service.getFoo() .subscribe(new Action1<Foo>(){ @Override public void call(Foo
foo){ doSomething(foo)); } }, new Action<Throwable>(){ @Override public void call(Throwable t){ Log.e(t); } }); RxAndroid | Richard Cirerol | @codeprogression
// Still need to cleanup subscription.unsubscribe(); RxAndroid | Richard Cirerol
| @codeprogression
RxJava = Observables + Operators + Schedulers RxAndroid | Richard
Cirerol | @codeprogression
Operators 4 Are a specialized observer 4 Can transform observables
4 Can be chained 4 A function that takes a Subscriber and returns a Subscriber RxAndroid | Richard Cirerol | @codeprogression
Observable.from({0, 1, 2, 3, 4}) .subscribe(); RxAndroid | Richard Cirerol
| @codeprogression
Observable.from({0, 1, 2, 3, 4}) .skip(1) .map(new Func1<Integer, Integer>(){ @Override
public Integer call(Integer in){ return in^2; } }) .subscribe(); RxAndroid | Richard Cirerol | @codeprogression
Observable.from({0, 1, 2, 3, 4}) .doOnNext(new Action1<Integer>(){ @Override public void
call(Integer in){ return Log.i("Received: " + in); } }) .subscribe(); RxAndroid | Richard Cirerol | @codeprogression
Observable<Player> player; Observable<List<Team>> teams; Observable.combineLatest(player, teams, new Func2<Player, List<Team>, ViewModel>(){
@Override public ViewModel(Player player, List<Team> teams){ Team team = teams.get(player.getTeamId()); return new ViewModel(player.getName(), team.getName()); } }) .subscribe(...); RxAndroid | Richard Cirerol | @codeprogression
Observables are asynchronous by default A subscription will not block
the thread when waiting for a value. RxAndroid | Richard Cirerol | @codeprogression
toBlocking() makes an Observable synchronous A subscription WILL block the
thread when waiting for a value. RxAndroid | Richard Cirerol | @codeprogression
RxJava = Observables + Operators + Schedulers RxAndroid | Richard
Cirerol | @codeprogression
Normally, operations are done on the current thread RxAndroid |
Richard Cirerol | @codeprogression
Schedulers RxJava allows you to marshall operations to another thread.
RxAndroid | Richard Cirerol | @codeprogression
Schedulers subscribeOn() and observeOn() are special operators RxAndroid | Richard
Cirerol | @codeprogression
subscribeOn() declares the starting Scheduler RxAndroid | Richard Cirerol |
@codeprogression
observeOn() declares the continuing Scheduler RxAndroid | Richard Cirerol |
@codeprogression
RxJava Default Schedulers RxAndroid | Richard Cirerol | @codeprogression
Schedulers.immediate() RxAndroid | Richard Cirerol | @codeprogression
Schedulers.trampoline() RxAndroid | Richard Cirerol | @codeprogression
Schedulers.newThread() RxAndroid | Richard Cirerol | @codeprogression
Schedulers.computation() RxAndroid | Richard Cirerol | @codeprogression
Schedulers.io() RxAndroid | Richard Cirerol | @codeprogression
Schedulers.test() RxAndroid | Richard Cirerol | @codeprogression
Schedulers.from(Executor executor) RxAndroid | Richard Cirerol | @codeprogression
RxAndroid = RxJava + Additional Schedulers RxAndroid | Richard Cirerol
| @codeprogression
AndroidSchedulers.mainThread() RxAndroid | Richard Cirerol | @codeprogression
HandlerScheduler.create(Looper looper) RxAndroid | Richard Cirerol | @codeprogression
Observable.create(s -> getFooFromWeb()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(); RxAndroid | Richard Cirerol
| @codeprogression
Observable.create(s -> getFooFromWeb()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .map(foo -> calculateBar(foo)) // !!
.subscribe(); RxAndroid | Richard Cirerol | @codeprogression
Observable.create(() -> getFooFromWeb()) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(foo -> calculateBar(foo)) .observeOn(AndroidSchedulers.mainThread()) .subscribe();
RxAndroid | Richard Cirerol | @codeprogression
Observable.create(s -> getFooFromWeb()) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(foo -> calculateBar(foo)) .observeOn(AndroidSchedulers.mainThread()) .subscribe();
RxAndroid | Richard Cirerol | @codeprogression
Let's break this up RxAndroid | Richard Cirerol | @codeprogression
// in publisher class public Observable<Bar> getBar(){ return Observable.create(s ->
getFooFromWeb()) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(foo -> calculateBar(foo)) } // in subscriber class (presenter?) getBar() .observeOn(AndroidSchedulers.mainThread()); .subscribe(item -> updateView(item)); RxAndroid | Richard Cirerol | @codeprogression
private Bar cachedBar; public Observable<Bar> getBar(){ return Observable.create(s -> getFooFromWeb())
.subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(foo -> calculateBar(foo)) .doOnNext(bar -> cachedBar = bar) } RxAndroid | Richard Cirerol | @codeprogression
private Bar cachedBar; public Observable<Bar> getBar(){ if (cachedBar != null){
return Observable.just(cachedBar); } else { return Observable.create(s -> getFooFromWeb()) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(foo -> calculateBar(foo)) .doOnNext(bar -> cachedBar = bar) } } RxAndroid | Richard Cirerol | @codeprogression
Rx in the Android Lifecycle RxAndroid | Richard Cirerol |
@codeprogression
public void onResume(){ subscription = publisher.getFoo().subscribe(...); } RxAndroid | Richard
Cirerol | @codeprogression
public void onResume(){ subscription = publisher.getFoo().subscribe(...); } public void onPause(){
subscription.unsubscribe(); } RxAndroid | Richard Cirerol | @codeprogression
public void onResume(){ subscription1 = publisher.getFoo().subscribe(...); subscription2 = publisher.getBar().subscribe(...); subscription3
= publisher.getBaz().subscribe(...); } public void onPause(){ subscription1.unsubscribe(); subscription2.unsubscribe(); subscription3.unsubscribe(); } RxAndroid | Richard Cirerol | @codeprogression
CompositeSubscription subscriptions; public void onResume(){ subscriptions = new CompositeSubscription(); subscriptions.add(publisher.getFoo().subscribe(...));
subscriptions.add(publisher.getBar().subscribe(...)); subscriptions.add(publisher.getBaz().subscribe(...)); } public void onPause(){ subscriptions.unsubscribe(); } RxAndroid | Richard Cirerol | @codeprogression
Warning Once unsubscribed, a CompositeSubscription will not manage any new
subscriptions. RxAndroid | Richard Cirerol | @codeprogression
Case Study RxAndroid | Richard Cirerol | @codeprogression
Case Study Problem: Retrieve a video url for a program
RxAndroid | Richard Cirerol | @codeprogression
Case Study Problem: Retrieve a video url for a program
RxAndroid | Richard Cirerol | @codeprogression
Intent intent = new Intent(this, VideoPlayerActivity.class); intent.putExtra("PROGRAM_ID", programId); startActivity(intent); RxAndroid
| Richard Cirerol | @codeprogression
String id = getIntent().getStringExtra("PROGRAM_ID", id); subscription = publisher.getVideoUrl(id) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new
Subscriber<String>(){ @Override public void onCompleted() {} @Override public void onError(final Throwable e) { } @Override public void onNext(final String url) { player.load(url); } }); RxAndroid | Richard Cirerol | @codeprogression
Retrofit 4 http://square.github.io/retrofit 4 Type-safe HTTP client 4 RxJava capable
(with adapter) RxAndroid | Richard Cirerol | @codeprogression
public interface VideoApi { @GET("/video/{id}") Observable<Video> getVideo(@Path("id") String id); }
RxAndroid | Richard Cirerol | @codeprogression
// VideoService.java public Observable<String> getVideoUrl(String id){ api.getVideo() // return a
url from the Video object } RxAndroid | Richard Cirerol | @codeprogression
map() Transform each item from one value to another RxAndroid
| Richard Cirerol | @codeprogression
// VideoService.java public Observable<String> getVideoUrl(String id){ api.getVideo() .map(new Func1<Video, String>{
@Override public String call(Video video){ return video.getUrl(); } }); } RxAndroid | Richard Cirerol | @codeprogression
// VideoService.java public Observable<String> getVideoUrl(String id){ api.getVideo() .subscribeOn(Schedules.io) .map(new Func1<Video,
String>(){ @Override public String call(Video video){ return video.getUrl(); } }); } RxAndroid | Richard Cirerol | @codeprogression
Web service calls aren't that simple. RxAndroid | Richard Cirerol
| @codeprogression
public interface VideoApi { @GET("/video/{id}") Observable<Video> getVideo( @Header("Authorization") auth, @Path("id")
String id); } RxAndroid | Richard Cirerol | @codeprogression
public interface VideoApi { @GET("/video/{id}") Observable<Video> getVideo( @Header("Authorization") auth, @Path("id")
String id); @POST("/token") Observable<String> getToken(@Body TokenRequest request); } RxAndroid | Richard Cirerol | @codeprogression
// VideoService.java public Observable<String> getVideoUrl(String id){ api.getToken(tokenRequest) .subscribeOn(Schedules.io) ... api.getVideo()
.map(new Func1<Video, String>{ @Override public String call(Video video){ return video.getUrl(); } }); } RxAndroid | Richard Cirerol | @codeprogression
Don't break the chain 4 Use operators to transform RxAndroid
| Richard Cirerol | @codeprogression
flatMap() Transform each item into one or more Observables, then
flatten RxAndroid | Richard Cirerol | @codeprogression
// VideoService.java private TokenRequest request; public Observable<String> getVideoUrl(final String id){
api.getToken(tokenRequestBody) .subscribeOn(Schedules.io) .flatMap(new Func1<String, Observable<Video>(){ @Override public Observable<Video> call(String token){ return api.getVideo(token, id); } }) .map(new Func1<Video, String>(){ @Override public String call(Video video){ return video.getUrl(); } }); } RxAndroid | Richard Cirerol | @codeprogression
RxAndroid = Observables + Operators + Schedulers + Additional Schedulers
RxAndroid | Richard Cirerol | @codeprogression
Observables 4 stream data to observers 4 also notify observers
of termination events RxAndroid | Richard Cirerol | @codeprogression
Operators 4 transform data 4 provide side effects 4 affect
either 4 items 4 observable RxAndroid | Richard Cirerol | @codeprogression
Schedulers 4 enable concurrency strategies RxAndroid | Richard Cirerol |
@codeprogression
Subscribers 4 act on the emitted items and notifications 4
are protected from synchronicity or concurrency concerns RxAndroid | Richard Cirerol | @codeprogression
http://reactivex.io http://http://blog.danlew.net RxAndroid | Richard Cirerol | @codeprogression
Richard Cirerol @codeprogression http://codeprogression.com RxAndroid | Richard Cirerol | @codeprogression
Thanks! RxAndroid | Richard Cirerol | @codeprogression