Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Async Android Jamie McDonald

Slide 3

Slide 3 text

@Override public void onCreate() { super.onCreate(); Log.i(TAG, “Hi from the main thread!”); } Main Thread title, date, 01 of 10

Slide 4

Slide 4 text

ANR title, date, 01 of 10

Slide 5

Slide 5 text

ANR title, date, 01 of 10 I/Choreographer﹕ Skipped 480 frames! The application may be doing too much work on its main thread.

Slide 6

Slide 6 text

@UiThread public void updateUi(String title) { textView.setText(title); } @WorkerThread public void showTitle() { textView.setText(SlowStuff.loadTitle()); } Tools title, date, 01 of 10

Slide 7

Slide 7 text

@UiThread public void updateUi(String title) { textView.setText(title); } @WorkerThread public void showTitle() { textView.setText(SlowStuff.loadTitle()); } Tools title, date, 01 of 10

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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));

Slide 11

Slide 11 text

new AsyncTask() { @Override protected String doInBackground(Void... params) { return SlowStuff.blocking(); } @Override protected void onPostExecute(String s) { updateUi(s); } }.execute(); AsyncTask title, date, 01 of 10

Slide 12

Slide 12 text

title, date, 01 of 10 “Painless threading” - The year 2009

Slide 13

Slide 13 text

new AsyncTask() { [...] @Override protected void onPostExecute(Result result) { if (result.isSuccess()) { doNextAsyncStep(result.getValue()); } else { // ??? } } }.execute(); Callback Hell title, date, 01 of 10

Slide 14

Slide 14 text

Execution Order title, date, 01 of 10 SERIAL SERIAL THREAD POOL

Slide 15

Slide 15 text

class DataLoader extends AsyncTaskLoader { public BackgroundLoader(Context context) { super(context); } @Override protected void onStartLoading() { forceLoad(); } @Override public String loadInBackground() { return SlowStuff.blocking(); } } Loader title, date, 01 of 10

Slide 16

Slide 16 text

getLoaderManager().initLoader(LOADER_ID, null, new LoaderManager.LoaderCallbacks() { @Override public Loader onCreateLoader(int id, Bundle args) { return new DataLoader(MainActivity.this); } @Override public void onLoadFinished(Loader loader, String text) { updateUi(text); } @Override public void onLoaderReset(Loader loader) { loader.reset(); } }); Loader title, date, 01 of 10

Slide 17

Slide 17 text

Enter RxJava!

Slide 18

Slide 18 text

RxJava title, date, 01 of 10 “RxJava tries to be very lightweight. [...] focused on just the Observable abstraction and related higher-order functions”

Slide 19

Slide 19 text

Observer Pattern title, date, 01 of 10

Slide 20

Slide 20 text

Streams title, date, 01 of 10

Slide 21

Slide 21 text

public Observable observable() { return Observable.create((subscriber) -> { subscriber.onNext(blocking()); subscriber.onCompleted(); }); } Observable title, date, 01 of 10

Slide 22

Slide 22 text

class MySubscriber extends DefaultSubscriber { @Override public void onNext(String text) { updateUi(text); } @Override public void onError(Throwable e) { displayError(e); } } Subscriber title, date, 01 of 10

Slide 23

Slide 23 text

SlowStuff.observable() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new MySubscriber()); Schedulers title, date, 01 of 10

Slide 24

Slide 24 text

title, date, 01 of 10 Thread IntentService AsyncTask Loader RxJava Main thread callbacks Configuration changes Error handling Composability Flexible scheduling

Slide 25

Slide 25 text

Operators title, date, 01 of 10 flatMap map filter doOnNext onErrorResumeNext distinct cache zip retry ...

Slide 26

Slide 26 text

FlatMap title, date, 01 of 10

Slide 27

Slide 27 text

trackOps.loadWaveformUrl(urn) .flatMap(url -> imageOps.renderWaveform(url)) .onErrorResumeNext(imageOps.defaultWaveform()) [...] .subscribe(new WaveformSubscriber()); FlatMap title, date, 01 of 10

Slide 28

Slide 28 text

OnErrorResumeNext title, date, 01 of 10

Slide 29

Slide 29 text

public final class EventQueue { static final Queue PLAYBACK_STATE; static final Queue PLAYBACK_PROGRESS; static final Queue PLAYABLE_CHANGED; [...] } Event Bus title, date, 01 of 10

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

title, date, 01 of 10

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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)

Slide 34

Slide 34 text

Downsides title, date, 01 of 10 Debugging Testing long call chains Learning curve Boilerplate Config changes Backpressure Where & when to use it?

Slide 35

Slide 35 text

*£#%@£$?? title, date, 01 of 10

Slide 36

Slide 36 text

More title, date, 01 of 10 RxAndroid Not RxAndroid Retrofit Retrolambda

Slide 37

Slide 37 text

soundcloud.com/jobs Thank you, NYC!