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
62
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
110
Introduction to Kotlin, Pt. 1
codeprogression
0
120
Android Studio Tips
codeprogression
0
96
Android: Testing Reactive MVP Applications
codeprogression
0
170
Unconventional Android v3
codeprogression
0
37
Unconventional Android v2
codeprogression
3
420
A Brief History of the Internet
codeprogression
1
490
Other Decks in Programming
See All in Programming
AWS re:Invent 2025参加 直前 Seattle-Tacoma Airport(SEA)におけるハードウェア紛失インシデントLT
tetutetu214
2
110
AIによる開発の民主化を支える コンテキスト管理のこれまでとこれから
mulyu
3
190
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
540
CSC307 Lecture 06
javiergs
PRO
0
680
責任感のあるCloudWatchアラームを設計しよう
akihisaikeda
3
170
Unicodeどうしてる? PHPから見たUnicode対応と他言語での対応についてのお伺い
youkidearitai
PRO
1
2.5k
Oxlint JS plugins
kazupon
1
860
20260127_試行錯誤の結晶を1冊に。著者が解説 先輩データサイエンティストからの指南書 / author's_commentary_ds_instructions_guide
nash_efp
1
940
Rust 製のコードエディタ “Zed” を使ってみた
nearme_tech
PRO
0
160
CSC307 Lecture 01
javiergs
PRO
0
690
例外処理とどう使い分ける?Result型を使ったエラー設計 #burikaigi
kajitack
16
6k
なるべく楽してバックエンドに型をつけたい!(楽とは言ってない)
hibiki_cube
0
140
Featured
See All Featured
Code Reviewing Like a Champion
maltzj
527
40k
Tell your own story through comics
letsgokoyo
1
810
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1k
Making the Leap to Tech Lead
cromwellryan
135
9.7k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
250
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
1
440
Being A Developer After 40
akosma
91
590k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.7k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
220
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
56
Faster Mobile Websites
deanohume
310
31k
How to Ace a Technical Interview
jacobian
281
24k
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