Slide 1

Slide 1 text

Android Reactive Programming with RxJava Mohammed Touban

Slide 2

Slide 2 text

Reactive Programming • Deal with asynchronous streams of data/events • Almost anything can be a stream • Single values • UI events • Individual items from a collection

Slide 3

Slide 3 text

Reactive Programming • User clicks on a View • We react by performing some logic in a click listener • Data loaded from an HTTP request • We react by displaying parsed data in a View • IOException thrown while doing I/O work • We react by displaying error message, logging error, etc.

Slide 4

Slide 4 text

Reactive Programming • So…callbacks? • Yes, but there’s more! • Callbacks are the main way we handle asynchronous events • Callbacks can add up…fast

Slide 5

Slide 5 text

Callback Hell • Logic may be split up across classes • Ordering of callback events can be hard to follow / visualize • Handling multiple threads can be difficult, or at best verbose • Error handling becomes verbose and reduces readability

Slide 6

Slide 6 text

Using Callbacks long friendId; void start() {
 service = retrofit.create(ApiService.class);
 service.getDetails().enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 friendId = response.body().friendId;
 getFriendDetails();
 }
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 } private void getFriendDetails() {
 service.getFriendDetails(friendId).enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {…}
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 }

Slide 7

Slide 7 text

Using Callbacks long friendId; void start() {
 service = retrofit.create(ApiService.class);
 service.getDetails().enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 friendId = response.body().friendId;
 getFriendDetails();
 }
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 } private void getFriendDetails() {
 service.getFriendDetails(friendId).enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {…}
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 }

Slide 8

Slide 8 text

Using Callbacks long friendId; void start() {
 service = retrofit.create(ApiService.class);
 service.getDetails().enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 friendId = response.body().friendId;
 getFriendDetails();
 }
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 } private void getFriendDetails() {
 service.getFriendDetails(friendId).enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {…}
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 }

Slide 9

Slide 9 text

Using Callbacks long friendId; void start() {
 service = retrofit.create(ApiService.class);
 service.getDetails().enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 friendId = response.body().friendId;
 getFriendDetails();
 }
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 } private void getFriendDetails() {
 service.getFriendDetails(friendId).enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {…}
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 }

Slide 10

Slide 10 text

Using Callbacks • Stateful environment leads to side effects • Side effects aren’t inherently bad, but can be unpredictable • Following the logic is not as clear as we’d like • How can we do better?

Slide 11

Slide 11 text

Functional Programming - Extreme Basics • Programming without assignments • Values are computed and shared with subsequent functions • This continues until you get your final result • No “state”

Slide 12

Slide 12 text

Functional Reactive Programming • Combining reactive programming with concepts of functional programming • Gives predictable results without worrying about “side-effects” (state) • Logic for a stream is concentrated in one place • Logic for each function can still be split out where it makes sense

Slide 13

Slide 13 text

Using Callbacks long friendId; void start() {
 service = retrofit.create(ApiService.class);
 service.getDetails().enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 friendId = response.body().friendId;
 getFriendDetails();
 }
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 } private void getFriendDetails() {
 service.getFriendDetails(friendId).enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {…}
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 }

Slide 14

Slide 14 text

Using Functional Reactive Programming void start() {
 service.getDetailsObservable()
 .flatMap(apiResponse -> service.getFriendDetailsObservable(apiResponse.friendId))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(friendDetails -> {…}, throwable -> {…});
 }

Slide 15

Slide 15 text

Using Functional Reactive Programming void start() {
 service.getDetailsObservable()
 .flatMap(apiResponse -> service.getFriendDetailsObservable(apiResponse.friendId))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(friendDetails -> {…}, throwable -> {…});
 }

Slide 16

Slide 16 text

Using Functional Reactive Programming void start() {
 service.getDetailsObservable()
 .flatMap(apiResponse -> service.getFriendDetailsObservable(apiResponse.friendId))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(friendDetails -> {…}, throwable -> {…});
 }

Slide 17

Slide 17 text

Using Functional Reactive Programming void start() {
 service.getDetailsObservable()
 .flatMap(apiResponse -> service.getFriendDetailsObservable(apiResponse.friendId))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(friendDetails -> {…}, throwable -> {…});
 }

Slide 18

Slide 18 text

Using Functional Reactive Programming void start() {
 service.getDetailsObservable()
 .flatMap(apiResponse -> service.getFriendDetailsObservable(apiResponse.friendId))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(friendDetails -> {…}, throwable -> {…});
 }

Slide 19

Slide 19 text

Using Functional Reactive Programming void start() {
 service.getDetailsObservable()
 .flatMap(apiResponse -> service.getFriendDetailsObservable(apiResponse.friendId))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(friendDetails -> {…}, throwable -> {…});
 }

Slide 20

Slide 20 text

Using Functional Reactive Programming • There are no assignments in the previous code sample • Logic is concise and easy to follow • Error handling is simplified • Imagine if yet another service call was needed in this chain

Slide 21

Slide 21 text

Hey…I could use Callbacks without assignment void start() {
 service = retrofit.create(ApiService.class);
 Call call = service.getDetails();
 call.enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 service.getFriendDetails(response.body().friendId).enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {…}
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 }
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 }

Slide 22

Slide 22 text

Hey…I could use Callbacks without assignment void start() {
 service = retrofit.create(ApiService.class);
 Call call = service.getDetails();
 call.enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 service.getFriendDetails(response.body().friendId).enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 service.getFriendMessages(response.body().id).enqueue(new Callback>() {
 @Override
 public void onResponse(Call> call, Response> response) {…}
 
 @Override public void onFailure(Call> call, Throwable t) {…}
 });
 }
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 }
 
 @Override public void onFailure(Call call, Throwable t) {…}
 });
 }

Slide 23

Slide 23 text

Using Functional Reactive Programming void stream() {
 service.getDetailsObservable()
 .flatMap(apiResponse -> service.getFriendDetailsObservable(apiResponse.friendId))
 .doOnNext(friendDetails -> {…})
 .flatMap(friendDetails -> service.getFriendMessagesObservable(friendDetails.id))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(friendMessages -> "", throwable -> );
 }

Slide 24

Slide 24 text

Using Functional Reactive Programming void stream() {
 service.getDetailsObservable()
 .flatMap(apiResponse -> service.getFriendDetailsObservable(apiResponse.friendId))
 .doOnNext(friendDetails -> {…})
 .flatMap(friendDetails -> service.getFriendMessagesObservable(friendDetails.id))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(friendMessages -> "", throwable -> );
 }

Slide 25

Slide 25 text

Reactive Extensions (Rx) • Framework developed by Microsoft • Many implementations of it across most popular languages • Rx.NET, RxJS, RxCpp, RxPy, UniRx (Unity C#), RxSwift, RxJava, RxKotlin

Slide 26

Slide 26 text

RxJava • Ported by Netflix • Version 1 was released in Nov 18, 2014 after 2 years of development • Version 2 is currently stable

Slide 27

Slide 27 text

RxJava • Extremely easy threading • Large amount of operators to transform your stream of data • Simplified error handling

Slide 28

Slide 28 text

RxJava • Steep learning curve • Going beyond AsyncTask replacement requires new mindset • Difficult to get yourself to “think reactive” • Easy to drop in piece-by-piece

Slide 29

Slide 29 text

RxJava • Observables • Observers • Operators

Slide 30

Slide 30 text

RxJava - Observables • Object that can be subscribed to by an Observer • Emits item(s) • Building block of the stream

Slide 31

Slide 31 text

RxJava - Observers • Subscribe to Observables • Three methods • onNext • onComplete • onError

Slide 32

Slide 32 text

RxJava - Observers • onNext - every emitted item from an Observable • onComplete - Observable finished emitting • onError - error thrown at any point in Observable chain

Slide 33

Slide 33 text

RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1() {
 @Override public void call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1() {
 @Override public void call(Throwable throwable) {
 Log.e("TAG", "Error in Observable chain", throwable);
 }
 }, new Action0() {
 @Override public void call() {
 Log.d("TAG", "Observable finished emitting items");
 }
 });

Slide 34

Slide 34 text

RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1() {
 @Override public void call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1() {
 @Override public void call(Throwable throwable) {
 Log.e("TAG", "Error in Observable chain", throwable);
 }
 }, new Action0() {
 @Override public void call() {
 Log.d("TAG", "Observable finished emitting items");
 }
 });

Slide 35

Slide 35 text

RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1() {
 @Override public void call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1() {
 @Override public void call(Throwable throwable) {
 Log.e("TAG", "Error in Observable chain", throwable);
 }
 }, new Action0() {
 @Override public void call() {
 Log.d("TAG", "Observable finished emitting items");
 }
 });

Slide 36

Slide 36 text

RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1() {
 @Override public void call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1() {
 @Override public void call(Throwable throwable) {
 Log.e("TAG", "Error in Observable chain", throwable);
 }
 }, new Action0() {
 @Override public void call() {
 Log.d("TAG", "Observable finished emitting items");
 }
 });

Slide 37

Slide 37 text

RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1() {
 @Override public void call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1() {
 @Override public void call(Throwable throwable) {
 Log.e("TAG", "Error in Observable chain", throwable);
 }
 }, new Action0() {
 @Override public void call() {
 Log.d("TAG", "Observable finished emitting items");
 }
 });

Slide 38

Slide 38 text

RxJava - Observers Observable.just("Hello")
 .subscribe(s -> Log.d("TAG", s),
 throwable -> Log.e("TAG", "Error in Observable chain", throwable),
 () -> Log.d("TAG", "Observable finished emitting items"));

Slide 39

Slide 39 text

RxJava - Observers Observable.just("Hello")
 .subscribe(s -> Log.d("TAG", s),
 throwable -> Log.e("TAG", "Error in Observable chain", throwable));

Slide 40

Slide 40 text

RxJava - Observers Observable.just("Hello")
 .subscribe(s -> Log.d("TAG", s));

Slide 41

Slide 41 text

RxJava - Observables • The building block of the chain • Operators for most any transformation you want to do • In charge of calling onNext/onComplete/onError • In charge of handling back pressure*

Slide 42

Slide 42 text

RxJava - Subjects public abstract class Subject extends Observable implements Observer • Observable and Observer • Good for bridging non-reactive API • Can act like a more explicit event bus

Slide 43

Slide 43 text

RxJava - Subjects public class NetworkChangeReceiver extends BroadcastReceiver {
 
 @Inject BehaviorSubject wifiSubject;
 
 @Override public void onReceive(Context context, Intent intent) {
 /* */
 boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
 wifiSubject.onNext(wifi);
 }
 } public class UploadService extends Service {
 
 @Inject BehaviorSubject wifiSubject;
 
 @Override public int onStartCommand(Intent intent, int flags, int startId) { /* */
 wifiSubject.subscribe(isWifi -> {
 if (isWifi) {
 startUpload();
 } else {
 pauseUpload();
 }
 });
 return super.onStartCommand(intent, flags, startId);
 }
 /* */
 }

Slide 44

Slide 44 text

RxJava - Subjects public class NetworkChangeReceiver extends BroadcastReceiver {
 
 @Inject BehaviorSubject wifiSubject;
 
 @Override public void onReceive(Context context, Intent intent) {
 /* */
 boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
 wifiSubject.onNext(wifi);
 }
 } public class UploadService extends Service {
 
 @Inject BehaviorSubject wifiSubject;
 
 @Override public int onStartCommand(Intent intent, int flags, int startId) {
 /* */
 wifiSubject.subscribe(isWifi -> {
 if (isWifi) {
 startUpload();
 } else {
 pauseUpload();
 }
 });
 return super.onStartCommand(intent, flags, startId);
 }
 /* */
 }

Slide 45

Slide 45 text

RxJava - Subjects public class NetworkChangeReceiver extends BroadcastReceiver {
 
 @Inject BehaviorSubject wifiSubject;
 
 @Override public void onReceive(Context context, Intent intent) {
 /* */
 boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
 wifiSubject.onNext(wifi);
 }
 } public class UploadService extends Service {
 
 @Inject BehaviorSubject wifiSubject;
 
 @Override public int onStartCommand(Intent intent, int flags, int startId) {
 /* */
 wifiSubject.subscribe(isWifi -> {
 if (isWifi) {
 startUpload();
 } else {
 pauseUpload();
 }
 });
 return super.onStartCommand(intent, flags, startId);
 }
 /* */
 }

Slide 46

Slide 46 text

RxJava - Operators • Can transform observable stream • Can give access to emitted items at any point in the stream • Can specify Schedulers to run on

Slide 47

Slide 47 text

RxJava - Operators • subscribeOn / observeOn getStringObservable()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(textView::setText);

Slide 48

Slide 48 text

RxJava - Operators • map • flatMap • zip / zipWith • combineLatest • filter • doOnNext

Slide 49

Slide 49 text

RxJava - Marble Diagrams

Slide 50

Slide 50 text

RxJava - Where to Start • AsyncTask replacement • Retrofit requests • List filtering*

Slide 51

Slide 51 text

Async Task RxJava ComputationTask computationTask = new ComputationTask(this);
 computationTask.execute("input"); /** **/ class ComputationTask extends AsyncTask {
 
 private final SearchMessagesTask.SearchListener listener;
 
 ComputationTask(SearchMessagesTask.SearchListener listener) {
 this.listener = listener;
 }
 
 @Override protected Long doInBackground(String... params) {
 return longRunningFunction(params[0]);
 }
 
 @Override protected void onPostExecute(Long result) {
 listener.computationCompleted(result);
 }
 } Observable.fromCallable(() -> longRunningFunction(“input”))
 .subscribeOn(Schedulers.computation())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::computationCompleted);

Slide 52

Slide 52 text

Async Task RxJava ComputationTask computationTask = new ComputationTask(this);
 computationTask.execute("input"); /** **/ class ComputationTask extends AsyncTask {
 
 private final SearchMessagesTask.SearchListener listener;
 
 ComputationTask(SearchMessagesTask.SearchListener listener) {
 this.listener = listener;
 }
 
 @Override protected Long doInBackground(String... params) {
 return longRunningFunction(params[0]);
 }
 
 @Override protected void onPostExecute(Long result) {
 listener.computationCompleted(result);
 }
 } Observable.fromCallable(() -> longRunningFunction(“input”))
 .subscribeOn(Schedulers.computation())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::computationCompleted);

Slide 53

Slide 53 text

Async Task RxJava SearchMessagesTask task = new SearchMessagesTask(this, allMessages);
 task.execute("Dinner"); /** **/ class SearchMessagesTask extends AsyncTask> {
 
 private final SearchListener listener;
 private final List allMessages;
 
 SearchMessagesTask(SearchListener listener, List allMessages) {
 this.listener = listener;
 this.allMessages = allMessages;
 }
 
 @Override protected List doInBackground(String... params) {
 String searchTerm = params[0];
 List messages = new ArrayList<>();
 for (Test.Message message : allMessages) {
 if (message.body.contains(searchTerm)) {
 messages.add(message);
 }
 }
 return messages;
 }
 
 @Override protected void onPostExecute(List messages) {
 listener.onSearchCompleted(messages);
 }
 } Observable.from(allMessages)
 .filter(message -> message.body.contains("Dinner"))
 .toList()
 .subscribeOn(Schedulers.computation())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::displayMessages);

Slide 54

Slide 54 text

Async Task RxJava SearchMessagesTask task = new SearchMessagesTask(this, allMessages);
 task.execute("Dinner"); /** **/ class SearchMessagesTask extends AsyncTask> {
 
 private final SearchListener listener;
 private final List allMessages;
 
 SearchMessagesTask(SearchListener listener, List allMessages) {
 this.listener = listener;
 this.allMessages = allMessages;
 }
 
 @Override protected List doInBackground(String... params) {
 String searchTerm = params[0];
 List messages = new ArrayList<>();
 for (Test.Message message : allMessages) {
 if (message.body.contains(searchTerm)) {
 messages.add(message);
 }
 }
 return messages;
 }
 
 @Override protected void onPostExecute(List messages) {
 listener.onSearchCompleted(messages);
 }
 } Observable.from(allMessages)
 .filter(message -> message.body.contains("Dinner"))
 .toList()
 .subscribeOn(Schedulers.computation())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::displayMessages);

Slide 55

Slide 55 text

Async Task RxJava SearchMessagesTask task = new SearchMessagesTask(this, allMessages);
 task.execute("Dinner"); /** **/ class SearchMessagesTask extends AsyncTask> {
 
 private final SearchListener listener;
 private final List allMessages;
 
 SearchMessagesTask(SearchListener listener, List allMessages) {
 this.listener = listener;
 this.allMessages = allMessages;
 }
 
 @Override protected List doInBackground(String... params) {
 String searchTerm = params[0];
 List messages = new ArrayList<>();
 for (Test.Message message : allMessages) {
 if (message.body.contains(searchTerm)) {
 messages.add(message);
 }
 }
 return messages;
 }
 
 @Override protected void onPostExecute(List messages) {
 listener.onSearchCompleted(messages);
 }
 } Observable.from(allMessages)
 .filter(message -> message.body.contains("Dinner"))
 .toList()
 .subscribeOn(Schedulers.computation())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::displayMessages);

Slide 56

Slide 56 text

Async Task RxJava SearchMessagesTask task = new SearchMessagesTask(this, allMessages);
 task.execute("Dinner"); /** **/ class SearchMessagesTask extends AsyncTask> {
 
 private final SearchListener listener;
 private final List allMessages;
 
 SearchMessagesTask(SearchListener listener, List allMessages) {
 this.listener = listener;
 this.allMessages = allMessages;
 }
 
 @Override protected List doInBackground(String... params) {
 String searchTerm = params[0];
 List messages = new ArrayList<>();
 for (Test.Message message : allMessages) {
 if (message.body.contains(searchTerm)) {
 messages.add(message);
 }
 }
 return messages;
 }
 
 @Override protected void onPostExecute(List messages) {
 listener.onSearchCompleted(messages);
 }
 } Observable.from(allMessages)
 .filter(message -> message.body.contains("Dinner"))
 .toList()
 .subscribeOn(Schedulers.computation())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::displayMessages);

Slide 57

Slide 57 text

Callback Observable service.getDetails().enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 handleResponse(response.body());
 }
 
 @Override public void onFailure(Call call, Throwable t) {
 handleError(t);
 }
 }); service.getDetailsObservable()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::handleResponse, this::handleError);

Slide 58

Slide 58 text

Callback Observable service.getDetails().enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 handleResponse(response.body());
 }
 
 @Override public void onFailure(Call call, Throwable t) {
 handleError(t);
 }
 }); service.getDetailsObservable()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::handleResponse, this::handleError);

Slide 59

Slide 59 text

Callback Observable service.getDetails().enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 handleResponse(response.body());
 }
 
 @Override public void onFailure(Call call, Throwable t) {
 handleError(t);
 }
 }); service.getDetailsObservable()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::handleResponse, this::handleError);

Slide 60

Slide 60 text

Callback Observable service.getDetails().enqueue(new Callback() {
 @Override
 public void onResponse(Call call, Response response) {
 handleResponse(response.body());
 }
 
 @Override public void onFailure(Call call, Throwable t) {
 handleError(t);
 }
 }); service.getDetailsObservable()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::handleResponse, this::handleError); retrofit = new Retrofit.Builder()
 .baseUrl("")
 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 .build(); implementation ‘com.squareup.retrofit2:adapter-rxjava:x.y.z’

Slide 61

Slide 61 text

For Loop Observable List filteredList = new ArrayList(); for (Integer integer : integers) {
 if (integer % 3 == 0) {
 filteredList.add(integer);
 }
 }
 return filteredList; Observable.from(integers)
 .filter(integer -> integer % 3 == 0)
 .toList()
 .subscribe(filteredList -> {});

Slide 62

Slide 62 text

Observable fromScratchUploadObservable() { return Observable.just(videoToUpload.videoFile.getUri()) .flatMap(vimeoUploadInformationObservableFactory::get) .flatMap(uploadFromScratchObservableFactory.get()) .flatMap(closeUploadTicket()) .flatMap(updateVideoMetaData()) .map(saveToBuilderTrend()) .subscribeOn(Schedulers.io()); } Observable resumeUploadObservable() { return Observable.just(videoToUpload.vimeoUploadInfo) .flatMap(resumeObservableFactory::get) .flatMap(closeUploadTicket()) .flatMap(updateVideoMetaData()) .map(saveToBuilderTrend()) .subscribeOn(Schedulers.io()); }

Slide 63

Slide 63 text

Helpful links RxJava Introduction Grokking RxJava series (Dan Lew) http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/ RxJava Advanced Demystifying RxJava Subscribers (Jake Wharton) https://vimeo.com/144812843 Rx Libraries Common RxJava Mistakes (Dan Lew) https://www.youtube.com/watch?v=QdmkXL7XikQ RxJava https://github.com/ReactiveX/RxJava RxAndroid https://github.com/ReactiveX/RxAndroid RxBinding https://github.com/JakeWharton/RxBinding RxRelay https://github.com/JakeWharton/RxRelay Loading data from multiple sources (Dan Lew) http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/ Learning RxJava by example (Kaushik Gopal) https://www.youtube.com/watch?v=k3D0cWyNno4 RxKotlin https://github.com/ReactiveX/RxKotlin