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

Reactive Programming with RxJava

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Reactive Programming with RxJava

An overview of the possibilities of cleaner code and more powerful functions available when using RxJava.

Full Keynote presentation file available here: https://drive.google.com/open?id=0B9sPCp06ijJWZkVZTWlLTWMtLVk

Avatar for Brandon Gogetap

Brandon Gogetap

September 14, 2016
Tweet

More Decks by Brandon Gogetap

Other Decks in Programming

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
  25. RxJava • Ported by Netflix • Version 1 is very

    robust, will be around and support for several years • Version 2 is currently in developer preview • Many changes, not a drop-in replacement for V1
  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(); compile ‘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 RxJava 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