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
Async Android
Search
Jamie McDonald
June 18, 2015
Programming
10
670
Async Android
NYC Android Developers Meetup, June 2015
Jamie McDonald
June 18, 2015
Tweet
Share
More Decks by Jamie McDonald
See All by Jamie McDonald
6 lessons learned scaling mobile
jdamcd
1
350
Android Engineering for Scale
jdamcd
13
2.2k
Other Decks in Programming
See All in Programming
CEDEC 2025 『ゲームにおけるリアルタイム通信への QUIC導入事例の紹介』
segadevtech
3
930
フロントエンドのmonorepo化と責務分離のリアーキテクト
kajitack
2
130
The State of Fluid (2025)
s2b
0
180
AI OCR API on Lambdaを Datadogで可視化してみた
nealle
0
130
サイトを作ったらNFCタグキーホルダーを爆速で作れ!
yuukis
0
390
CEDEC2025 長期運営ゲームをあと10年続けるための0から始める自動テスト ~4000項目を50%自動化し、月1→毎日実行にした3年間~
akatsukigames_tech
0
140
Go製CLIツールをnpmで配布するには
syumai
2
1.2k
実践 Dev Containers × Claude Code
touyu
1
220
Terraform やるなら公式スタイルガイドを読もう 〜重要項目 10選〜
hiyanger
13
3.2k
AIに安心して任せるためにTypeScriptで一意な型を作ろう
arfes0e2b3c
0
380
ライブ配信サービスの インフラのジレンマ -マルチクラウドに至ったワケ-
mirrativ
1
250
管你要 trace 什麼、bpftrace 用下去就對了 — COSCUP 2025
shunghsiyu
0
440
Featured
See All Featured
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
36
2.5k
How GitHub (no longer) Works
holman
314
140k
Facilitating Awesome Meetings
lara
55
6.5k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
229
22k
Unsuck your backbone
ammeep
671
58k
How to Ace a Technical Interview
jacobian
279
23k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.4k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
31
2.2k
Practical Orchestrator
shlominoach
190
11k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
890
YesSQL, Process and Tooling at Scale
rocio
173
14k
Code Review Best Practice
trishagee
70
19k
Transcript
None
Async Android Jamie McDonald
@Override public void onCreate() { super.onCreate(); Log.i(TAG, “Hi from the
main thread!”); } Main Thread title, date, 01 of 10
ANR title, date, 01 of 10
ANR title, date, 01 of 10 I/Choreographer﹕ Skipped 480 frames!
The application may be doing too much work on its main thread.
@UiThread public void updateUi(String title) { textView.setText(title); } @WorkerThread public
void showTitle() { textView.setText(SlowStuff.loadTitle()); } Tools title, date, 01 of 10
@UiThread public void updateUi(String title) { textView.setText(title); } @WorkerThread public
void showTitle() { textView.setText(SlowStuff.loadTitle()); } Tools title, date, 01 of 10
new Thread() { public void run() { final String result
= SlowStuff.blocking(); new Handler().post(new Runnable() { @Override public void run() { updateUi(result); } }); } }.start(); Thread title, date, 01 of 10
class LooperThread extends Thread { private Handler handler; public void
run() { Looper.prepare(); handler = new Handler() { public void handleMessage(Message msg) { // Process messages here } }; Looper.loop(); } } Looper title, date, 01 of 10
IntentService title, date, 01 of 10 public class BackgroundService extends
IntentService { public BackgroundService() { super("BackgroundWork"); } @Override protected void onHandleIntent(Intent intent) { SlowStuff.blocking(); } } startService(new Intent(this, BackgroundService.class));
new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params)
{ return SlowStuff.blocking(); } @Override protected void onPostExecute(String s) { updateUi(s); } }.execute(); AsyncTask title, date, 01 of 10
title, date, 01 of 10 “Painless threading” - The year
2009
new AsyncTask<Void, Void, Result>() { [...] @Override protected void onPostExecute(Result
result) { if (result.isSuccess()) { doNextAsyncStep(result.getValue()); } else { // ??? } } }.execute(); Callback Hell title, date, 01 of 10
Execution Order title, date, 01 of 10 SERIAL SERIAL THREAD
POOL
class DataLoader extends AsyncTaskLoader<String> { public BackgroundLoader(Context context) { super(context);
} @Override protected void onStartLoading() { forceLoad(); } @Override public String loadInBackground() { return SlowStuff.blocking(); } } Loader title, date, 01 of 10
getLoaderManager().initLoader(LOADER_ID, null, new LoaderManager.LoaderCallbacks<String>() { @Override public Loader<String> onCreateLoader(int id,
Bundle args) { return new DataLoader(MainActivity.this); } @Override public void onLoadFinished(Loader<String> loader, String text) { updateUi(text); } @Override public void onLoaderReset(Loader<String> loader) { loader.reset(); } }); Loader title, date, 01 of 10
Enter RxJava!
RxJava title, date, 01 of 10 “RxJava tries to be
very lightweight. [...] focused on just the Observable abstraction and related higher-order functions”
Observer Pattern title, date, 01 of 10
Streams title, date, 01 of 10
public Observable<String> observable() { return Observable.create((subscriber) -> { subscriber.onNext(blocking()); subscriber.onCompleted();
}); } Observable title, date, 01 of 10
class MySubscriber extends DefaultSubscriber<String> { @Override public void onNext(String text)
{ updateUi(text); } @Override public void onError(Throwable e) { displayError(e); } } Subscriber title, date, 01 of 10
SlowStuff.observable() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new MySubscriber()); Schedulers title, date, 01 of
10
title, date, 01 of 10 Thread IntentService AsyncTask Loader RxJava
Main thread callbacks Configuration changes Error handling Composability Flexible scheduling
Operators title, date, 01 of 10 flatMap map filter doOnNext
onErrorResumeNext distinct cache zip retry ...
FlatMap title, date, 01 of 10
trackOps.loadWaveformUrl(urn) .flatMap(url -> imageOps.renderWaveform(url)) .onErrorResumeNext(imageOps.defaultWaveform()) [...] .subscribe(new WaveformSubscriber()); FlatMap title,
date, 01 of 10
OnErrorResumeNext title, date, 01 of 10
public final class EventQueue { static final Queue<StateTransition> PLAYBACK_STATE; static
final Queue<ProgressEvent> PLAYBACK_PROGRESS; static final Queue<PlayableEvent> PLAYABLE_CHANGED; [...] } Event Bus title, date, 01 of 10
None
title, date, 01 of 10
Subtitle title, date, 01 of 10 eventBus.queue(EventQueue.PLAYABLE_CHANGE) .filter(PlayableEvent.IS_TRACK_FILTER) .doOnNext(updateLikeCount) .observeOn(AndroidSchedulers.mainThread())
Only listen to interesting events
Subtitle Respond to state without storing it title, date, 01
of 10 Observable.combineLatest( eventBus.queue(EventQueue.PLAY_QUEUE_TRACK), eventBus.queue(EventQueue.PLAYER_UI), combineStates) .doOnNext(setTrackHasBeenSeen)
Downsides title, date, 01 of 10 Debugging Testing long call
chains Learning curve Boilerplate Config changes Backpressure Where & when to use it?
*£#%@£$?? title, date, 01 of 10
More title, date, 01 of 10 RxAndroid Not RxAndroid Retrofit
Retrolambda
soundcloud.com/jobs Thank you, NYC!