intro to retrofit 2 and rxjava2
TRANSCRIPT
Introduction to Retrofit 2 and RxJava 2
Fabio Collini
Google I/O extended Florence May 2017
2
Ego slide
@fabioCollini linkedin.com/in/fabiocollini github.com/fabioCollini medium.com/@fabioCollini codingjam.it Android programmazione avanzata
3
Retrofit
Turns your REST API into a Java interface Simple to use JSON conversion using Gson Custom converters …
4
RxJava
A Java VM implementation of ReactiveX (Reactive Extensions): a library for composing asynchronous
and event-based programs by using observable sequences.
5
RxJava is not simple…
6
github.com/fabioCollini/IntroToRetrofit2RxJava2
Demo project
7
HTTP request definition
public interface StackOverflowService { @GET("/users") Call<List<User>> getTopUsers();
@GET("/users/{userId}/top-tags") Call<List<Tag>> getTags(@Path("userId") int userId); @GET("/users/{userId}/badges") Call<List<Badge>> getBadges(@Path("userId") int userId);}
8
Other annotations
@GET, @POST, @PUT, @DELETE, @HEAD @Path @Query @QueryMap @Body @FormUrlEncoded @Field @Headers
OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(chain -> { Request request = chain.request(); HttpUrl url = request.url().newBuilder() .addQueryParameter("site", "stackoverflow") .addQueryParameter("key", “...”) .build(); request = request.newBuilder().url(url).build(); return chain.proceed(request); }) .build();Gson gson = new GsonBuilder() .registerTypeAdapterFactory(MyAdapterFactory.create()) .create();
StackOverflowService service = new Retrofit.Builder() .baseUrl("http://api.stackexchange.com/2.2/") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(okHttpClient) .addConverterFactory(new DenvelopingConverter(gson)) .addConverterFactory(GsonConverterFactory.create(gson)) .build() .create(StackOverflowService.class);
9
Service creation
10
Synchronous request
try { Response<List<User>> response = service.getTopUsers().execute(); if (response.isSuccessful()) { List<User> users = response.body(); //... } else { //server error } } catch (IOException e) { //connection error}
11
Asynchronous request
service.getTopUsers().enqueue(new Callback<List<User>>() { @Override public void onResponse(Call<List<User>> call, Response<List<User>> r) { if (r.isSuccessful()) { List<User> users = response.body(); //... } else { //server error } } @Override public void onFailure(Call<List<User>> call, Throwable t) { //connection error } });
12
Callback hell enqueue(service.getTopUsers(), new MyCallback<List<User>>() { @Override public void onResponse(List<User> users) { User user = users.get(0); enqueue(service.getTags(user.id()), new MyCallback<List<Tag>>() { @Override public void onResponse(List<Tag> tags) { enqueue(service.getBadges(user.id()), new MyCallback<List<Badge>>() { @Override public void onResponse(List<Badge> badges) { callback.onResponse(UserStats.create(user, tags, badges)); } @Override public void onFailure(Throwable throwable) { callback.onFailure(throwable); } }); } @Override public void onFailure(Throwable throwable) { callback.onFailure(throwable); } }); } @Override public void onFailure(Throwable throwable) { callback.onFailure(throwable); }});
+ RxJavaRetrofit
13
public interface StackOverflowService { @GET("/users") Call<List<User>> getTopUsers();}_
14
Retrofit + RxJava
public interface StackOverflowService { @GET("/users") Single<List<User>> getTopUsers();}_
15
RxJava in action
service.getTopUsers() .subscribe( users -> { if (users.size() > 5) users = users.subList(0, 5); System.out.println(users); }, Throwable::printStackTrace );
16
Threading
service.getTopUsers() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread) .subscribe( users -> { if (users.size() > 5) users = users.subList(0, 5); System.out.println(users); }, Throwable::printStackTrace );
17
Single
(onSuccess | onError)?
18
Observable
onNext* (onComplete | onError)?
19
Observable creation
Observable.just(1, 2, 3);
Observable.interval(5, TimeUnit.SECONDS);
Observable.fromCallable(() -> { //... return createFirstValue();});
Observable.create(emitter -> { try { emitter.onNext(createFirstValue()); emitter.onNext(createSecondValue()); emitter.onComplete(); } catch (Throwable t) { emitter.onError(t); }});
20
Observable in action
public Disposable subscribe( Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete);
Observable.just(1, 2, 3).subscribe( System.out::println, Throwable::printStackTrace, () -> System.out.println("Completed") );
22
service.getTopUsers() .subscribe( users -> { if (users.size() > 5) users = users.subList(0, 5); System.out.println(users); }, Throwable::printStackTrace );
23
service.getTopUsers() .map(users -> users.size() > 5 ? users.subList(0, 5) : users) .subscribe( System.out::println, Throwable::printStackTrace );
25
zip
private Single<UserStats> loadUserStats(User user) { return Single.zip( service.getBadges(user.id()),__ service.getTags(user.id()),___ (badges, tags) -> UserStats.create(user, tags, badges) );}_
26
zip
private Single<UserStats> loadUserStats(User user) { return Single.zip( service.getBadges(user.id()).subscribeOn(Schedulers.io()),__ service.getTags(user.id()).subscribeOn(Schedulers.io()),___ (badges, tags) -> UserStats.create(user, tags, badges) );}_
27
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]]
29
map
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]
[1, 2, 3] [[10, 11], [20, 21], [30, 31]]
Observable<Observable<Integer>> observable = Observable.just(1, 2, 3).map( i -> Observable.just(i * 10, i * 10 + 1) );
flatMap
30
flatMap
Single<Profile> single = service.login(userName, password) .flatMap(service::getProfile);
31
service.getTopUsers() //1 List<20 User> .map(users -> users.size() > 5 ? users.subList(0, 5) : users) //1 List<5 User>
32
service.getTopUsers() //1 List<20 User> .map(users -> users.size() > 5 ? users.subList(0, 5) : users) //1 List<5 User> .flatMapObservable(users -> Observable.fromIterable(users)) //5 User
33
service.getTopUsers() //1 List<20 User> .map(users -> users.size() > 5 ? users.subList(0, 5) : users) //1 List<5 User> .flattenAsObservable(users -> users) // 5 User
34
service.getTopUsers() //1 List<20 User> .flattenAsObservable(users -> users) // 20 User .take(5) // 5 User
35
service.getTopUsers() //1 List<20 User> .flattenAsObservable(users -> users) // 20 User .take(5) // 5 User .flatMapSingle(user -> loadUserStats(service, user)) // 5 UserStats
36
Single<List<UserStats>> single = service.getTopUsers() //1 List<20 User> .flattenAsObservable(users -> users) // 20 User .take(5) // 5 User .flatMapSingle(user -> loadUserStats(service, user)) // 5 UserStats .toList(); // 1 List<5 UserStats>
37
Single<List<UserStats>> single = service.getTopUsers() //1 List<20 User> .flattenAsObservable(users -> users) // 20 User .take(5) // 5 User .flatMapSingle(user -> loadUserStats(service, user)) // 5 UserStats .toList(); // 1 List<5 UserStats>
single.subscribe( UserStats::printList, Throwable::printStackTrace);
38
730.876 Darin Dimitrov (Sofia, Bulgaria) c# (7.260), asp.net-mvc (6.780), asp.net-mvc-3 (4.629), jquery (3.043), asp.net (3.455) Teacher, Student, Editor, Cleanup, Organizer 724.614 BalusC (Amsterdam, Netherlands) java (6.468), jsf (6.957), jsf-2 (3.809), servlets (2.234), jsp (2.860) php, regex, servlets, java, security 677.074 VonC (France) git (8.555), eclipse (1.715), github (2.417), java (951), version-control (1.075) c, python, php, regex, c# 692.535 Hans Passant (Madison, WI) c# (8.199), .net (4.254), winforms (2.485), c++ (2.084), vb.net (1.457) Tag Editor, Announcer, reference, c, excel 944.295 Jon Skeet (Reading, United Kingdom) c# (18.363), java (10.213), .net (5.338), linq (2.879), string (954) cryptography, reference, c, python, php
Single<List<UserStats>> single = service.getTopUsers() //1 List<20 User> .flattenAsObservable(users -> users) // 20 User .take(5) // 5 User .flatMapSingle(user -> loadUserStats(service, user)) // 5 UserStats .toList(); // 1 List<5 UserStats>
single.subscribe( UserStats::printList, Throwable::printStackTrace);
39
flatMap source code (RxJava1)
public final <R> Observable<R> flatMap( Func1< ? super T, ? extends Observable<? extends R> > func) { return merge(map(func)); }
42
Single<List<UserStats>> single = service.getTopUsers() //1 List<20 User> .flattenAsObservable(users -> users) // 20 User .take(5) // 5 User .concatMapEager(user -> loadUserStats(service, user).toObservable()) // 5 User .toList(); // 1 List<5 UserStats>
single.subscribe( UserStats::printList, Throwable::printStackTrace);
43
944.295 Jon Skeet (Reading, United Kingdom) c# (18.363), java (10.213), .net (5.338), linq (2.879), string (954) cryptography, reference, c, python, php 730.876 Darin Dimitrov (Sofia, Bulgaria) c# (7.260), asp.net-mvc (6.780), asp.net-mvc-3 (4.629), jquery (3.043), asp.net (3.455) Teacher, Student, Editor, Cleanup, Organizer 724.614 BalusC (Amsterdam, Netherlands) java (6.468), jsf (6.957), jsf-2 (3.809), servlets (2.234), jsp (2.860) php, regex, servlets, java, security 692.535 Hans Passant (Madison, WI) c# (8.199), .net (4.254), winforms (2.485), c++ (2.084), vb.net (1.457) Tag Editor, Announcer, reference, c, excel 677.074 VonC (France) git (8.555), eclipse (1.715), github (2.417), java (951), version-control (1.075) c, python, php, regex, c#
Single<List<UserStats>> single = service.getTopUsers() //1 List<20 User> .flattenAsObservable(users -> users) // 20 User .take(5) // 5 User .concatMapEager(user -> loadUserStats(service, user).toObservable()) // 5 User .toList(); // 1 List<5 UserStats>
single.subscribe( UserStats::printList, Throwable::printStackTrace);
44
service.getTopUsers() .flattenAsObservable(users -> users) .take(5) .concatMapEager(user -> Single.zip( service.getBadges(user.id()).subscribeOn(Schedulers.io()), service.getTags(user.id()).subscribeOn(Schedulers.io()), (badges, tags) -> UserStats.create(user, tags, badges) ).toObservable()) .toList() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( UserStats::printList, Throwable::printStackTrace );
Wrapping up
45
This is just the beginning…
Observable class contains more than 400 methods: distinct, debounce, retry, repeat, timeout, …
disposable error management Single, Observable, Flowable, Completable, Maybe hot and cold observable subjects TestScheduler
github.com/fabioCollini/IntroToRetrofit2RxJava2
@fabioCollini linkedin.com/in/fabiocollini github.com/fabioCollini medium.com/@fabioCollini
Thanks for your attention!Questions?