Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Reactive Programming

Android Reactive Programming

A quick look at some of the ways RxJava can make development easier and more enjoyable (specifically for Android).
This talk was presented at Google devfest Lebanon 2017.
https://www.meetup.com/GDG-Coast-Lebanon/events/241810435/

Mohammed Touban

November 25, 2017
Tweet

More Decks by Mohammed Touban

Other Decks in Technology

Transcript

  1. Reactive Programming • Deal with asynchronous streams of data/events •

    Almost anything can be a stream • Single values • UI events • Individual items from a collection
  2. 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.
  3. Reactive Programming • So…callbacks? • Yes, but there’s more! •

    Callbacks are the main way we handle asynchronous events • Callbacks can add up…fast
  4. 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
  5. Using Callbacks long friendId; void start() {
 service = retrofit.create(ApiService.class);


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


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


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


    service.getDetails().enqueue(new Callback<ApiResponse>() {
 @Override
 public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
 friendId = response.body().friendId;
 getFriendDetails();
 }
 
 @Override public void onFailure(Call<ApiResponse> call, Throwable t) {…}
 });
 } private void getFriendDetails() {
 service.getFriendDetails(friendId).enqueue(new Callback<FriendDetails>() {
 @Override
 public void onResponse(Call<FriendDetails> call, Response<FriendDetails> response) {…}
 
 @Override public void onFailure(Call<FriendDetails> call, Throwable t) {…}
 });
 }
  9. 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?
  10. 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”
  11. 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
  12. Using Callbacks long friendId; void start() {
 service = retrofit.create(ApiService.class);


    service.getDetails().enqueue(new Callback<ApiResponse>() {
 @Override
 public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
 friendId = response.body().friendId;
 getFriendDetails();
 }
 
 @Override public void onFailure(Call<ApiResponse> call, Throwable t) {…}
 });
 } private void getFriendDetails() {
 service.getFriendDetails(friendId).enqueue(new Callback<FriendDetails>() {
 @Override
 public void onResponse(Call<FriendDetails> call, Response<FriendDetails> response) {…}
 
 @Override public void onFailure(Call<FriendDetails> call, Throwable t) {…}
 });
 }
  13. Using Functional Reactive Programming void start() {
 service.getDetailsObservable()
 .flatMap(apiResponse ->

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

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

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

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

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

    service.getFriendDetailsObservable(apiResponse.friendId))
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(friendDetails -> {…}, throwable -> {…});
 }
  19. 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
  20. Hey…I could use Callbacks without assignment void start() {
 service

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

    = retrofit.create(ApiService.class);
 Call<ApiResponse> call = service.getDetails();
 call.enqueue(new Callback<ApiResponse>() {
 @Override
 public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
 service.getFriendDetails(response.body().friendId).enqueue(new Callback<FriendDetails>() {
 @Override
 public void onResponse(Call<FriendDetails> call, Response<FriendDetails> response) {
 service.getFriendMessages(response.body().id).enqueue(new Callback<List<Message>>() {
 @Override
 public void onResponse(Call<List<Message>> call, Response<List<Message>> response) {…}
 
 @Override public void onFailure(Call<List<Message>> call, Throwable t) {…}
 });
 }
 
 @Override public void onFailure(Call<FriendDetails> call, Throwable t) {…}
 });
 }
 
 @Override public void onFailure(Call<ApiResponse> call, Throwable t) {…}
 });
 }
  22. 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 -> );
 }
  23. 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 -> );
 }
  24. 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
  25. RxJava • Ported by Netflix • Version 1 was released

    in Nov 18, 2014 after 2 years of development • Version 2 is currently stable
  26. RxJava • Extremely easy threading • Large amount of operators

    to transform your stream of data • Simplified error handling
  27. 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
  28. RxJava - Observables • Object that can be subscribed to

    by an Observer • Emits item(s) • Building block of the stream
  29. RxJava - Observers • onNext - every emitted item from

    an Observable • onComplete - Observable finished emitting • onError - error thrown at any point in Observable chain
  30. RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1<String>() {
 @Override public void

    call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1<Throwable>() {
 @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");
 }
 });
  31. RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1<String>() {
 @Override public void

    call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1<Throwable>() {
 @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");
 }
 });
  32. RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1<String>() {
 @Override public void

    call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1<Throwable>() {
 @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");
 }
 });
  33. RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1<String>() {
 @Override public void

    call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1<Throwable>() {
 @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");
 }
 });
  34. RxJava - Observers Observable.just("Hello")
 .subscribe(new Action1<String>() {
 @Override public void

    call(String s) {
 Log.d("TAG", s); // Logs "Hello"
 }
 }, new Action1<Throwable>() {
 @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");
 }
 });
  35. 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"));
  36. 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*
  37. RxJava - Subjects public abstract class Subject<T, R> extends Observable<R>

    implements Observer<T> • Observable and Observer • Good for bridging non-reactive API • Can act like a more explicit event bus
  38. RxJava - Subjects public class NetworkChangeReceiver extends BroadcastReceiver {
 


    @Inject BehaviorSubject<Boolean> 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<Boolean> 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);
 }
 /* */
 }
  39. RxJava - Subjects public class NetworkChangeReceiver extends BroadcastReceiver {
 


    @Inject BehaviorSubject<Boolean> 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<Boolean> 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);
 }
 /* */
 }
  40. RxJava - Subjects public class NetworkChangeReceiver extends BroadcastReceiver {
 


    @Inject BehaviorSubject<Boolean> 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<Boolean> 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);
 }
 /* */
 }
  41. RxJava - Operators • Can transform observable stream • Can

    give access to emitted items at any point in the stream • Can specify Schedulers to run on
  42. RxJava - Operators • map • flatMap • zip /

    zipWith • combineLatest • filter • doOnNext
  43. Async Task RxJava ComputationTask computationTask = new ComputationTask(this);
 computationTask.execute("input"); /**

    **/ class ComputationTask extends AsyncTask<String, Void, Long> {
 
 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);
  44. Async Task RxJava ComputationTask computationTask = new ComputationTask(this);
 computationTask.execute("input"); /**

    **/ class ComputationTask extends AsyncTask<String, Void, Long> {
 
 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);
  45. Async Task RxJava SearchMessagesTask task = new SearchMessagesTask(this, allMessages);
 task.execute("Dinner");

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

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

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

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

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

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

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

    Response<ApiResponse> response) {
 handleResponse(response.body());
 }
 
 @Override public void onFailure(Call<ApiResponse> 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’
  53. For Loop Observable List<Integer> filteredList = new ArrayList<Integer>(); for (Integer

    integer : integers) {
 if (integer % 3 == 0) {
 filteredList.add(integer);
 }
 }
 return filteredList; Observable.from(integers)
 .filter(integer -> integer % 3 == 0)
 .toList()
 .subscribe(filteredList -> {});
  54. Observable<Void> fromScratchUploadObservable() { return Observable.just(videoToUpload.videoFile.getUri()) .flatMap(vimeoUploadInformationObservableFactory::get) .flatMap(uploadFromScratchObservableFactory.get()) .flatMap(closeUploadTicket()) .flatMap(updateVideoMetaData()) .map(saveToBuilderTrend())

    .subscribeOn(Schedulers.io()); } Observable<Void> resumeUploadObservable() { return Observable.just(videoToUpload.vimeoUploadInfo) .flatMap(resumeObservableFactory::get) .flatMap(closeUploadTicket()) .flatMap(updateVideoMetaData()) .map(saveToBuilderTrend()) .subscribeOn(Schedulers.io()); }
  55. 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