Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Introduction to Retrofit and RxJava

5,177 views

Published on

How to use RxJava and Retrofit in an Android application to retrieve data from a REST server

Published in: Engineering
  • Dating direct: ♥♥♥ http://bit.ly/39mQKz3 ♥♥♥
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Dating for everyone is here: ❶❶❶ http://bit.ly/39mQKz3 ❶❶❶
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Introduction to Retrofit and RxJava

  1. 1. Introduction to Retrofit and RxJava AppDays 2015 Pordenone
  2. 2. Ego slide @fabioCollini linkedin.com/in/fabiocollini Folder Organizer GDG Firenze cosenonjaviste.it nana bianca Freapp instal.com Rain tomorrow? 2
  3. 3. Retrofit •  Turns your REST API into a Java interface •  Simple to use •  JSON conversion using Gson •  Custom converters •   … 3
  4. 4. RxJava RxJava is a Java VM implementation of ReactiveX (Reactive Extensions): a library for composing asynchronous and event-based programs by using observable sequences. github.com/ReactiveX/RxJava “ 4
  5. 5. RxJava is not simple… 5
  6. 6. Demo project github.com/fabioCollini/IntroToRetrofitRxJava 6
  7. 7. HTTP request definition public interface StackOverflowService { @GET("/users") UserResponse getTopUsers(); } 01. 02. 03. 04. 05. 06. 7
  8. 8. HTTP request definition public interface StackOverflowService { @GET("/users") UserResponse getTopUsers(); } public class UserResponse { private List<User> items; public List<User> getItems() { return items; } } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 8
  9. 9. Service creation RestAdapter restAdapter = new RestAdapter.Builder() 01. 02. 9
  10. 10. Service creation RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("http://api.stackexchange.com/2.2/") 01. 02. 03. 10
  11. 11. Service creation RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("http://api.stackexchange.com/2.2/") .build(); 01. 02. 03. 04. 11
  12. 12. Service creation RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("http://api.stackexchange.com/2.2/") .build(); StackOverflowService service = restAdapter.create(StackOverflowService.class); 01. 02. 03. 04. 05. 06. 12
  13. 13. Service creation RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("http://api.stackexchange.com/2.2/") .setRequestInterceptor(request -> { request.addQueryParam("site", "stackoverflow"); request.addQueryParam("key", "..."); }) .build(); StackOverflowService service = restAdapter.create(StackOverflowService.class); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 13
  14. 14. Synchronous request private List<User> loadItemsSync() { List<User> users = service.getTopUsers().getItems(); if (users.size() > 5) { users = users.subList(0, 5); } return users; } 01. 02. 03. 04. 05. 06. 07. 08. 14
  15. 15. Request parameters @GET("/users/{userId}/top-tags") TagResponse getTags(@Path("userId") int userId); @GET("/users/{userId}/badges") BadgeResponse getBadges(@Path("userId") int userId); 01. 02. 03. 04. 05. 15
  16. 16. Request parameters @GET("/users/{userId}/top-tags") TagResponse getTags(@Path("userId") int userId); @GET("/users/{userId}/badges") BadgeResponse getBadges(@Path("userId") int userId); service.getTags(12345); /users/12345/top-tags?site=stackoverflow&key=… 01. 02. 03. 04. 05. 16
  17. 17. Other annotations •  @GET, @POST, @PUT, @DELETE, @HEAD •  @Path •  @Query •  @QueryMap •  @Body •  @FormUrlEncoded •  @Field •  @Headers 17
  18. 18. Composition List<User> users = service.getTopUsers().getItems(); if (users.size() > 5) { users = users.subList(0, 5); } List<UserStats> statsList = new ArrayList<>(); for (User user : users) { TagResponse tags = service.getTags(user.getId()); BadgeResponse badges = service.getBadges(user.getId()); statsList.add(new UserStats(user, tags.getItems(), badges.getItems())); } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 18
  19. 19. AsyncTask new AsyncTask<Void, Void, List<User>>() { @Override protected List<User> doInBackground(Void... p) { try { return loadItemsSync(); } catch (Exception e) { return null; } } @Override protected void onPostExecute(List<User> users) { if (users != null) { adapter.addAll(users); } else { showError(); } } }.execute(); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19
  20. 20. Synchronous request public interface StackOverflowService { @GET("/users") UserResponse getTopUsers(); } 01. 02. 03. 04. 05. 06. 20
  21. 21. Callbacks public interface StackOverflowService { @GET("/users") void getTopUsers(Callback<UserResponse> callback); } 01. 02. 03. 04. 05. 06. 21
  22. 22. Callbacks in action service.getTopUsers(new Callback<UserResponse>() { @Override public void success( UserResponse userResponse, Response r) { List<User> users = userResponse.getItems(); if (users.size() > 5) users = users.subList(0, 5); adapter.addAll(users); } @Override public void failure(RetrofitError e) { showError(); } }); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 22
  23. 23. Callbacks in action service.getTopUsers(new Callback<UserResponse>() { @Override public void success( UserResponse userResponse, Response r) { List<User> users = userResponse.getItems(); if (users.size() > 5) users = users.subList(0, 5); adapter.addAll(users); } @Override public void failure(RetrofitError e) { showError(); } }); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 23
  24. 24. Callback hell service.getBadges(userId, new Callback<BadgeResponse>() { @Override public void success(BadgeResponse badges, Response r) { service.getTags(userId, new Callback<TagResponse>() { @Override public void success(TagResponse tags, Response r) { callback.success(new UserStats(user, tags.getItems(), badges.getItems()), r); } @Override public void failure(RetrofitError error) { callback.failure(error); } }); } @Override public void failure(RetrofitError error) { callback.failure(error); } }); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 24
  25. 25. Retrofit public interface StackOverflowService { @GET("/users") void getTopUsers(Callback<UserResponse> callback); } 01. 02. 03. 04. 05. 06. 25
  26. 26. Retrofit + RxJava public interface StackOverflowService { @GET("/users") Observable<UserResponse> getTopUsers(); } 01. 02. 03. 04. 05. 06. 26
  27. 27. RxJava in action service.getTopUsers() .subscribe(new Action1<UserResponse>() { @Override public void call(UserResponse r) { List<User> users = r.getItems(); if (users.size() > 5) users = users.subList(0, 5); adapter.addAll(users); } }, new Action1<Throwable>() { @Override public void call(Throwable t) { showError(); } }); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 27
  28. 28. Java 8 / Retrolambda service.getTopUsers() .subscribe( r -> { List<User> users = r.getItems(); if (users.size() > 5) users = users.subList(0, 5); adapter.addAll(users); }, t -> showError() ); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 28
  29. 29. Threading service .getTopUsers() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( r -> { List<User> users = r.getItems() if (users.size() > 5) users = users.subList(0, 5); adapter.addAll(users); }, t -> showError() ); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 29
  30. 30. subscribe public final Subscription subscribe( final Action1<? super T> onNext, final Action1<Throwable> onError) { //... } 01. 02. 03. 04. 05. 30
  31. 31. onNext | onError 31
  32. 32. onNext* (onComplete | onError)? 32
  33. 33. Observable creation Observable.just(1, 2, 3); 33
  34. 34. Observable creation Observable.just(1, 2, 3); Observable.from(Arrays.asList("A", "B", "C", "D")); 01. 02. 34
  35. 35. Observable creation Observable.just(1, 2, 3); Observable.from(Arrays.asList("A", "B", "C", "D")); Observable.error(new IOException()); 01. 02. 03. 35
  36. 36. Observable creation Observable.just(1, 2, 3); Observable.from(Arrays.asList("A", "B", "C", "D")); Observable.error(new IOException()); Observable.interval(5, TimeUnit.SECONDS); 01. 02. 03. 04. 36
  37. 37. Observable creation Observable.just(1, 2, 3); Observable.from(Arrays.asList("A", "B", "C", "D")); Observable.error(new IOException()); Observable.interval(5, TimeUnit.SECONDS); Observable.create(subscriber -> { try { subscriber.onNext(createFirstValue()); subscriber.onNext(createSecondValue()); subscriber.onCompleted(); } catch (Throwable t) { subscriber.onError(t); } }); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 37
  38. 38. Observable in action public Subscription subscribe( Action1<? super T> onNext, Action1<Throwable> onError, Action0 onComplete ); 01. 02. 03. 04. 05. 38
  39. 39. Observable in action public Subscription subscribe( Action1<? super T> onNext, Action1<Throwable> onError, Action0 onComplete ); Observable.just(1, 2, 3).subscribe( System.out::println, Throwable::printStackTrace, () -> System.out.println("Completed") ); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 39
  40. 40. Observer Observable.just(1, 2, 3) .subscribe(new Observer<Integer>() { @Override public void onNext(Integer i) { System.out.println(i); } @Override public void onError(Throwable t) { t.printStackTrace(); } @Override public void onCompleted() { System.out.println("Completed"); } }); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 40
  41. 41. map 41
  42. 42. map service.getTopUsers() .subscribe( r -> { List<User> users = r.getItems() if (users.size() > 5) users = users.subList(0, 5); adapter.addAll(users); }, t -> showError() ); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 42
  43. 43. map service.getTopUsers() .map(r -> r.getItems()) .subscribe( users -> { if (users.size() > 5) users = users.subList(0, 5); adapter.addAll(users); }, t -> showError() ); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 43
  44. 44. map service.getTopUsers() .map(r -> r.getItems()) .map(users -> users.size() > 5 ? users.subList(0, 5) : users) .subscribe( users -> adapter.addAll(users), t -> showError() ); 01. 02. 03. 04. 05. 06. 07. 08. 44
  45. 45. map service.getTopUsers() .map(UserResponse::getItems) .map(users -> users.size() > 5 ? users.subList(0, 5) : users) .subscribe( adapter::addAll, t -> showError() ); 01. 02. 03. 04. 05. 06. 07. 08. 45
  46. 46. zip 46
  47. 47. zip Observable.zip( service.getTags(user.getId()), service.getBadges(user.getId()), (tags, badges) -> new UserStats( user, tags.getItems(), badges.getItems()) ) ); 01. 02. 03. 04. 05. 06. 07. 08. 47
  48. 48. zip Observable.zip( service.getTags(user.getId()), service.getBadges(user.getId()), (tags, badges) -> new UserStats( user, tags.getItems(), badges.getItems()) ) ); 01. 02. 03. 04. 05. 06. 07. 08. 48
  49. 49. zip Observable.zip( service.getTags(user.getId()), service.getBadges(user.getId()), (tags, badges) -> new UserStats( user, tags.getItems(), badges.getItems()) ) ); 01. 02. 03. 04. 05. 06. 07. 08. 49
  50. 50. zip Observable.zip( service.getTags(user.getId()), service.getBadges(user.getId()), (tags, badges) -> new UserStats( user, tags.getItems(), badges.getItems()) ) ); 01. 02. 03. 04. 05. 06. 07. 08. 50
  51. 51. zip Observable.zip( service.getTags(user.getId()), service.getBadges(user.getId()), (tags, badges) -> new UserStats( user, tags.getItems(), badges.getItems() ) ); 01. 02. 03. 04. 05. 06. 07. 08. 51
  52. 52. zip Observable.zip( service.getTags(user.getId()) .map(TagResponse::getItems), service.getBadges(user.getId()) .map(BadgeResponse::getItems), (tags, badges) -> new UserStats(user, tags, badges) ); 01. 02. 03. 04. 05. 06. 07. 08. 52
  53. 53. Multi value map Observable.just(1, 2, 3).map( i -> Observable.just(i * 10, i * 10 + 1) ); 01. 02. 03. 53
  54. 54. Multi value map Observable<Observable<Integer>> observable = Observable.just(1, 2, 3).map( i -> Observable.just(i * 10, i * 10 + 1) ); 01. 02. 03. 04. 54
  55. 55. Multi value map Observable<Observable<Integer>> observable = Observable.just(1, 2, 3).map( i -> Observable.just(i * 10, i * 10 + 1) ); [1, 2, 3] [[10, 11], [20, 21], [30, 31]] 01. 02. 03. 04. 05. 06. 07. 08. 55
  56. 56. flatMap 56
  57. 57. flatMap Observable<Integer> observable = Observable.just(1, 2, 3).flatMap( i -> Observable.just(i * 10, i * 10 + 1) ); [1, 2, 3] [10, 11, 20, 21, 30, 31] 01. 02. 03. 04. 05. 06. 07. 08. 57
  58. 58. flatMap Observable<Profile> observable = service.login(userName, password) .flatMap(token -> service.getProfile(token)); 01. 02. 03. 58
  59. 59. flatMap Observable<Profile> observable = service.login(userName, password) .flatMap(token -> service.getProfile(token)); Observable<Profile> observable = service.login(userName, password) .flatMap(service::getProfile); 01. 02. 03. 04. 05. 06. 07. 59
  60. 60. flatMap service .getTopUsers()//1<UserResponse> 01. 02. 60
  61. 61. flatMap service .getTopUsers()//1<UserResponse> .flatMap(r -> Observable.from(r.getItems())) //20<User> 01. 02. 03. 04. 61
  62. 62. flatMap service .getTopUsers()//1<UserResponse> .flatMapIterable(UserResponse::getItems)//20<User> 01. 02. 03. 62
  63. 63. flatMap service .getTopUsers()//1<UserResponse> .flatMapIterable(UserResponse::getItems)//20<User> .limit(5)//5<User> 01. 02. 03. 04. 63
  64. 64. flatMap service .getTopUsers()//1<UserResponse> .flatMapIterable(UserResponse::getItems)//20<User> .limit(5)//5<User> .flatMap(this::loadUserStats)//5<UserStats> 01. 02. 03. 04. 05. 64
  65. 65. flatMap service .getTopUsers()//1<UserResponse> .flatMapIterable(UserResponse::getItems)//20<User> .limit(5)//5<User> .flatMap(this::loadUserStats)//5<UserStats> .toList();//1<List<UserStats>> 01. 02. 03. 04. 05. 06. 65
  66. 66. Order is not preserved 66
  67. 67. flatMap source code public final <R> Observable<R> flatMap( Func1< ? super T, ? extends Observable<? extends R> > func) { return merge(map(func)); } 01. 02. 03. 04. 05. 06. 07. 67
  68. 68. concatMap 68
  69. 69. concatMap source code public final <R> Observable<R> concatMap( Func1< ? super T, ? extends Observable<? extends R> > func) { return concat(map(func)); } 01. 02. 03. 04. 05. 06. 07. 69
  70. 70. concatMap service .getTopUsers() .flatMapIterable(UserResponse::getItems) .limit(5) .concatMap(this::loadUserStats) .toList(); 01. 02. 03. 04. 05. 06. 70
  71. 71. timeout service .getTopUsers() .flatMapIterable(UserResponse::getItems) .limit(5) .concatMap(this::loadRepoStats) .toList() .timeout(20, TimeUnit.SECONDS); 01. 02. 03. 04. 05. 06. 07. 71
  72. 72. retry service .getTopUsers() .retry(2) .flatMapIterable(UserResponse::getItems) .limit(5) .concatMap(this::loadRepoStats) .toList() .timeout(20, TimeUnit.SECONDS) .retry(1); 01. 02. 03. 04. 05. 06. 07. 08. 09. 72
  73. 73. Cache public class Cache { private List<UserStats> items; public void save(List<UserStats> users) { items = users; } public Observable<List<UserStats>> load( Throwable t) { if (items == null) return Observable.error(t); else return Observable.just(items); } } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 73
  74. 74. doOnNext / onErrorResumeNext service.getTopUsers() .retry(2) .flatMapIterable(UserResponse::getItems) .limit(5) .concatMap(this::loadRepoStats) .toList() .timeout(20, TimeUnit.SECONDS) .retry(1) .doOnNext(cache::save) .onErrorResumeNext(cache::load); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 74
  75. 75. Subscription Observable .interval(1, TimeUnit.SECONDS) .timestamp() .subscribe(System.out::println); 01. 02. 03. 04. 75
  76. 76. Subscription Subscription subscription = Observable .interval(1, TimeUnit.SECONDS) .timestamp() .subscribe(System.out::println); Thread.sleep(2500); subscription.unsubscribe(); 01. 02. 03. 04. 05. 06. 07. 08. 76
  77. 77. Subscription Subscription subscription = Observable .interval(1, TimeUnit.SECONDS) .timestamp() .subscribe(System.out::println); Thread.sleep(2500); subscription.unsubscribe(); Timestamped(timestampMillis = 1429360406807, value = 0) Timestamped(timestampMillis = 1429360407805, value = 1) 01. 02. 03. 04. 05. 06. 07. 08. 77
  78. 78. How many requests? Observable<UserResponse> observable = service.getTopUsers(); Subscription s1 = observable.subscribe( System.out::println, Throwable::printStackTrace); Subscription s2 = observable.subscribe( System.out::println, Throwable::printStackTrace); 01. 02. 03. 04. 05. 06. 07. 78
  79. 79. How many requests? Observable<UserResponse> observable = service.getTopUsers(); Subscription s1 = observable.subscribe( System.out::println, Throwable::printStackTrace); Subscription s2 = observable.subscribe( System.out::println, Throwable::printStackTrace); •  2 requests •  Retrofit Observables are cold 01. 02. 03. 04. 05. 06. 07. 79
  80. 80. Hot observables Observable<UserResponse> observable = service.getTopUsers(); ConnectableObservable<UserResponse> replayObservable = observable.replay(1); Subscription s1 = replayObservable.subscribe( System.out::println, Throwable::printStackTrace); Subscription s2 = replayObservable.subscribe( System.out::println, Throwable::printStackTrace); Subscription s3 = replayObservable.connect(); 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 80
  81. 81. Activity lifecycle @Override public View onCreateView(...) { ... retainedFragment = RetainedFragment .getOrCreate(getActivity()); if (retainedFragment.get() == null) { Observable<List<T>> observable = loadItems() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); retainedFragment.bind(observable.replay(1)); } ... } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 81
  82. 82. Activity lifecycle @Override public void onResume() { super.onResume(); subscription = retainedFragment.get() .subscribe( this::showDataInList, t -> showError() ); } @Override public void onPause() { super.onPause(); subscription.unsubscribe(); } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 82
  83. 83. RetainedFragment public class RetainedFragment<T> extends Fragment { private Subscription connectableSubscription = Subscriptions.empty(); private ConnectableObservable<T> observable; public RetainedFragment() { setRetainInstance(true); } public void bind(ConnectableObservable<T> observable) { this.observable = observable; connectableSubscription = observable.connect(); } @Override public void onDestroy() { super.onDestroy(); connectableSubscription.unsubscribe(); } public Observable<T> get() { return observable; } } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 83
  84. 84. RetainedFragment public class RetainedFragment<T> extends Fragment { private Subscription connectableSubscription = Subscriptions.empty(); private ConnectableObservable<T> observable; public RetainedFragment() { setRetainInstance(true); } public void bind(ConnectableObservable<T> observable) { this.observable = observable; connectableSubscription = observable.connect(); } @Override public void onDestroy() { super.onDestroy(); connectableSubscription.unsubscribe(); } public Observable<T> get() { return observable; } } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 84
  85. 85. RetainedFragment public class RetainedFragment<T> extends Fragment { private Subscription connectableSubscription = Subscriptions.empty(); private ConnectableObservable<T> observable; public RetainedFragment() { setRetainInstance(true); } public void bind(ConnectableObservable<T> observable) { this.observable = observable; connectableSubscription = observable.connect(); } @Override public void onDestroy() { super.onDestroy(); connectableSubscription.unsubscribe(); } public Observable<T> get() { return observable; } } 01. 02. 03. 04. 05. 06. 07. 08. 09. 10. 11. 12. 13. 14. 15. 16. 17. 18. 85
  86. 86. Thanks for your attention! Questions?   github.com/fabioCollini/IntroToRetrofitRxJava   @fabioCollini linkedin.com/in/fabiocollini cosenonjaviste.it 86 @fabioCollini cosenonjaviste.it

×