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
60
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
120
Android Studio Tips
codeprogression
0
94
Android: Testing Reactive MVP Applications
codeprogression
0
160
Unconventional Android v3
codeprogression
0
34
Unconventional Android v2
codeprogression
3
420
A Brief History of the Internet
codeprogression
1
480
Other Decks in Programming
See All in Programming
ご注文の差分はこちらですか? 〜 AWS CDK のいろいろな差分検出と安全なデプロイ
konokenj
3
370
MCPを使ってイベントソーシングのAIコーディングを効率化する / Streamlining Event Sourcing AI Coding with MCP
tomohisa
0
150
Rubyでやりたい駆動開発 / Ruby driven development
chobishiba
1
740
テスト駆動Kaggle
isax1015
1
480
顧客の画像データをテラバイト単位で配信する 画像サーバを WebP にした際に起こった課題と その対応策 ~継続的な取り組みを添えて~
takutakahashi
1
150
PHPでWebSocketサーバーを実装しよう2025
kubotak
0
300
Git Sync を超える!OSS で実現する CDK Pull 型デプロイ / Deploying CDK with PipeCD in Pull-style
tkikuc
3
150
A full stack side project webapp all in Kotlin (KotlinConf 2025)
dankim
0
130
なぜ適用するか、移行して理解するClean Architecture 〜構造を超えて設計を継承する〜 / Why Apply, Migrate and Understand Clean Architecture - Inherit Design Beyond Structure
seike460
PRO
3
780
NPOでのDevinの活用
codeforeveryone
0
870
CDK引数設計道場100本ノック
badmintoncryer
1
240
AIともっと楽するE2Eテスト
myohei
7
2.9k
Featured
See All Featured
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
20
1.3k
Documentation Writing (for coders)
carmenintech
72
4.9k
Become a Pro
speakerdeck
PRO
29
5.4k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
15
1.6k
Automating Front-end Workflow
addyosmani
1370
200k
Building Adaptive Systems
keathley
43
2.7k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.3k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
KATA
mclloyd
30
14k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
130
19k
BBQ
matthewcrist
89
9.7k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
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