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

Making Retrofit Work For You (Droidcon UK 2016)

Making Retrofit Work For You (Droidcon UK 2016)

Retrofit's recently-released version 2 is the easiest way to do HTTP in your applications. Once set up, Retrofit is designed to make declaring endpoints as simple as a method on an interface with annotations. Behind that simplicity, though, there is a lot of power and knowing how to use and configure it can make even the most problematic APIs easy to use.

This talk will focus on configuring three parts of Retrofit:

* Endpoint declarations on interfaces which define how requests are created and sent and how their responses are read and parsed.

* Serialization customization that goes beyond just choosing between JSON or Protocol Buffers.

* Execution mechanisms which enable synchronous or asynchronous requests, integration with third-party libraries, and custom error handling.

You will not need prior Retrofit experience, although the focus will specifically be on configuring and customizing its behavior.

Video: https://skillsmatter.com/skillscasts/8416-making-retrofit-2-work-for-you

Jake Wharton

October 28, 2016
Tweet

More Decks by Jake Wharton

Other Decks in Programming

Transcript

  1. Retrofit interface ApiService { List<User> search( String query, SortOrder order);

    }A class HttpApiService implements ApiService { // ... }
  2. Retrofit interface ApiService { @GET("/search/{category}") Call<List<User>> search( @Path("category") String category,

    @Query("q") String query, @Query("sort") SortOrder order); @POST("/upload/image") Call<Void> uploadImage( @Body Image image); }A
  3. Retrofit interface ApiService { @GET("/search/{category}") Call<List<User>> search( @Path("category") String category,

    @Query("q") String query, @Query("sort") SortOrder order); @POST("/upload/image") @Headers("SomeHeader: SomeValue") Call<Void> uploadImage( @Body Image image); }A
  4. Retrofit interface ApiService { // ... }A Retrofit retrofit =

    new Retrofit.Builder()
 .baseUrl("http://example.com")
 .build();
  5. Retrofit interface ApiService { // ... }A Retrofit retrofit =

    new Retrofit.Builder()
 .baseUrl("http://example.com")
 .build(); ApiService service = retrofit.create(ApiService.class);
  6. Retrofit interface ApiService { // ... }A Retrofit retrofit =

    new Retrofit.Builder()
 .baseUrl("http://example.com")
 .build(); ApiService service = retrofit.create(ApiService.class);
  7. HTTP Client Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .build(); Foo

    foo = retrofit.create(Foo.class); Bar bar = retrofit.create(Bar.class);
  8. HTTP Client Retrofit retrofitFoo = new Retrofit.Builder()
 .baseUrl("http://foo.example.com")
 .build(); Foo

    foo = retrofitFoo.create(Foo.class); Retrofit retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com")
 .build(); Bar bar = retrofitBar.create(Bar.class);
  9. HTTP Client Retrofit retrofitFoo = new Retrofit.Builder()
 .baseUrl("http://foo.example.com") .client(new OkHttpClient())


    .build(); Foo foo = retrofitFoo.create(Foo.class); Retrofit retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com") .client(new OkHttpClient())
 .build(); Bar bar = retrofitBar.create(Bar.class);
  10. HTTP Client Retrofit retrofitFoo = new Retrofit.Builder()
 .baseUrl("http://foo.example.com") .client(new OkHttpClient())


    .build(); Foo foo = retrofitFoo.create(Foo.class); Retrofit retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com") .client(new OkHttpClient())
 .build(); Bar bar = retrofitBar.create(Bar.class); OkHttpClient client =
  11. HTTP Client OkHttpClient client = new OkHttpClient(); Retrofit retrofitFoo =

    new Retrofit.Builder()
 .baseUrl("http://foo.example.com") .client(client)
 .build(); Foo foo = retrofitFoo.create(Foo.class); Retrofit retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com") .client(client)
 .build(); Bar bar = retrofitBar.create(Bar.class); new OkHttpClient()
  12. HTTP Client OkHttpClient client = new OkHttpClient(); Retrofit retrofitFoo =

    new Retrofit.Builder()
 .baseUrl("http://foo.example.com") .client(client)
 .build(); Foo foo = retrofitFoo.create(Foo.class); Retrofit retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com") .client(client)
 .build(); Bar bar = retrofitBar.create(Bar.class);
  13. HTTP Client OkHttpClient client = new OkHttpClient(); OkHttpClient clientFoo =

    client.newBuilder() .addInterceptor(new FooInterceptor()) .build();
  14. HTTP Client OkHttpClient client = new OkHttpClient(); OkHttpClient clientFoo =

    client.newBuilder() .addInterceptor(new FooInterceptor()) .build(); OkHttpClient clientBar = client.newBuilder() .readTimeout(30, SECONDS) .writeTimeout(30, SECONDS) .build();
  15. HTTP Client interface Service {
 @GET("/user")
 Call<User> user();
 
 @POST("/login")


    Call<User> login(@Body LoginRequest request);
 @GET("/logout")
 Call<Void> logout();
 }X
  16. HTTP Client interface Service {
 @GET("/user") // Requires authentication.
 Call<User>

    user();
 
 @POST("/login") // Does not require authentication.
 Call<User> login(@Body LoginRequest request);
 @GET("/logout") // Requires authentication.
 Call<Void> logout();
 }X
  17. HTTP Client class ServiceInterceptor implements Interceptor {
 @Override public Response

    intercept(Chain chain) {
 Request request = chain.request();
 return chain.proceed(request);
 }B
 }A
  18. HTTP Client class ServiceInterceptor implements Interceptor {
 @Override public Response

    intercept(Chain chain) {
 Request request = chain.request(); 
 if (!request.url().encodedPath().equals("/login")) {
 request = request.newBuilder()
 .addHeader("Authorization", "hunter2")
 .build();
 } 
 return chain.proceed(request);
 }B
 }A
  19. HTTP Client class ServiceInterceptor implements Interceptor {
 @Override public Response

    intercept(Chain chain) {
 Request request = chain.request(); 
 if (!request.url().encodedPath().equals("/login")) {
 request = request.newBuilder()
 .addHeader("Authorization", "hunter2")
 .build();
 } 
 return chain.proceed(request);
 }
 }
  20. HTTP Client interface Service {
 @GET("/user") // Requires authentication.
 Call<User>

    user();
 
 @POST("/login") // Does not require authentication.
 Call<User> login(@Body LoginRequest request);
 @GET("/logout") // Requires authentication.
 Call<Void> logout();
 }X
  21. HTTP Client interface Service {
 @GET("/user") // Requires authentication.
 Call<User>

    user();
 
 @POST("/login") // Does not require authentication.
 Call<User> login(@Body LoginRequest request);
 
 @POST("/forgotPassword") // Does not require authentication.
 Call<Void> forgotPassword(@Body ForgotPasswordRequest request);
 @GET("/logout") // Requires authentication.
 Call<Void> logout();
 }X
  22. HTTP Client interface Service {
 @GET("/user") // Requires authentication.
 Call<User>

    user();
 
 @POST("/login") // Does not require authentication.
 Call<User> login(@Body LoginRequest request);
 
 @POST("/forgotPassword") // Does not require authentication.
 Call<Void> forgotPassword(@Body ForgotPasswordRequest request);
 @GET("/logout") // Requires authentication.
 Call<Void> logout();
 }X class ServiceInterceptor implements Interceptor {
 @Override public Response intercept(Chain chain) {
 Request request = chain.request(); 
 if (!request.url().encodedPath().equals("/login")) {
 request = request.newBuilder()
 .addHeader("Authorization", "hunter2")
 .build();
 } 
 return chain.proceed(request);
 }
 }
  23. HTTP Client interface Service {
 @GET("/user") // Requires authentication.
 Call<User>

    user();
 
 @POST("/login") // Does not require authentication.
 Call<User> login(@Body LoginRequest request);
 
 @POST("/forgotPassword") // Does not require authentication.
 Call<Void> forgotPassword(@Body ForgotPasswordRequest request);
 @GET("/logout") // Requires authentication.
 Call<Void> logout();
 }X
  24. HTTP Client interface Service {
 @GET("/user")
 Call<User> user();
 
 @POST("/login")

    // Does not require authentication.
 Call<User> login(@Body LoginRequest request);
 
 @POST("/forgotPassword") // Does not require authentication.
 Call<Void> forgotPassword(@Body ForgotPasswordRequest request);
 @GET("/logout")
 Call<Void> logout();
 }X
  25. HTTP Client interface Service {
 @GET("/user")
 Call<User> user();
 
 @POST("/login")

    @Headers("No-Authentication: true")
 Call<User> login(@Body LoginRequest request);
 
 @POST("/forgotPassword") @Headers("No-Authentication: true")
 Call<Void> forgotPassword(@Body ForgotPasswordRequest request);
 @GET("/logout")
 Call<Void> logout();
 }X 
 
 
 
 // Does not require authentication. 
 
 
 // Does not require authentication.
  26. HTTP Client interface Service {
 @GET("/user")
 Call<User> user();
 
 @POST("/login")

    @Headers("No-Authentication: true")
 Call<User> login(@Body LoginRequest request);
 
 @POST("/forgotPassword") @Headers("No-Authentication: true")
 Call<Void> forgotPassword(@Body ForgotPasswordRequest request);
 @GET("/logout")
 Call<Void> logout();
 }X 
 
 
 
 // Does not require authentication. 
 
 
 // Does not require authentication.
  27. HTTP Client class ServiceInterceptor implements Interceptor {
 @Override public Response

    intercept(Chain chain) {
 Request request = chain.request(); 
 if (!request.url().encodedPath().equals("/login")) {
 request = request.newBuilder()
 .addHeader("Authorization", "hunter2")
 .build();
 }C 
 return chain.proceed(request);
 }B
 }A
  28. HTTP Client class ServiceInterceptor implements Interceptor {
 @Override public Response

    intercept(Chain chain) {
 Request request = chain.request(); 
 if (request.header("No-Authentication") == null) {
 request = request.newBuilder()
 .addHeader("Authorization", "hunter2")
 .build();
 }C 
 return chain.proceed(request);
 }B
 }A 
 
 
 ! url().encodedPath().equals("/login")
  29. HTTP Client class ServiceInterceptor implements Interceptor {
 @Override public Response

    intercept(Chain chain) {
 Request request = chain.request(); 
 if (request.header("No-Authentication") == null) {
 request = request.newBuilder()
 .addHeader("Authorization", "hunter2")
 .build();
 }C 
 return chain.proceed(request);
 }B
 }A
  30. HTTP Client OkHttpClient client = new OkHttpClient(); Retrofit retrofit =

    new Retrofit.Builder()
 .baseUrl("http://example.com") Z.client(client)
 .build(); Service foo = retrofit.create(Service.class);
  31. HTTP Client OkHttpClient client = new OkHttpClient(); Retrofit retrofit =

    new Retrofit.Builder()
 .baseUrl("http://example.com") Z.callFactory(client)
 .build(); Service foo = retrofit.create(Service.class); 
 client
  32. HTTP Client OkHttpClient client = new OkHttpClient(); Retrofit retrofit =

    new Retrofit.Builder()
 .baseUrl("http://example.com") .callFactory(client)
 .build(); Service foo = retrofit.create(Service.class);
  33. HTTP Client interface Call { Response execute(); void enqueue(Callback cb);

    interface Factory { Call newCall(Request r); } }
  34. HTTP Client interface Call { // OkHttp's Call, not Retrofit's

    Call<T>. Response execute(); void enqueue(Callback cb); interface Factory { Call newCall(Request r); } }
  35. HTTP Client interface Call { // OkHttp's Call, not Retrofit's

    Call<T>. Response execute(); void enqueue(Callback cb); interface Factory { Call newCall(Request r); } } interface Callback {} class Request {} class RequestBody {} class Response {} class ResponseBody {} class Headers {}
  36. HTTP Client class ApacheCallFactory implements Call.Factory { private HttpClient client;

    @Override public Call newCall(Request request) { return new Call() { @Override public Response execute() { return fromApache(client.execute(toApache(request))); } @Override public void enqueue(Callback callback) { throw new UnsupportedOperationException(); } }; } static Response fromApache(HttpResponse response) {} static HttpRequest toApache(Request request) {} }
  37. Converters Retrofit retrofitFoo = new Retrofit.Builder()
 .baseUrl("http://foo.example.com")
 .addConverterFactory(GsonConverterFactory.create())
 .build(); Retrofit

    retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com")
 .addConverterFactory(GsonConverterFactory.create())
 .build();
  38. Converters Retrofit retrofitFoo = new Retrofit.Builder()
 .baseUrl("http://foo.example.com")
 .addConverterFactory(GsonConverterFactory.create())
 .build(); Retrofit

    retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com")
 .addConverterFactory(GsonConverterFactory.create())
 .build();
  39. Converters Retrofit retrofitFoo = new Retrofit.Builder()
 .baseUrl("http://foo.example.com")
 .addConverterFactory(GsonConverterFactory.create())A
 .build(); Retrofit

    retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com")
 .addConverterFactory(GsonConverterFactory.create())B
 .build();
  40. Converters GsonConverterFactory gsonFactory = GsonConverterFactory.create(); Retrofit retrofitFoo = new Retrofit.Builder()


    .baseUrl("http://foo.example.com")
 .addConverterFactory(gsonFactory)A
 .build(); Retrofit retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com")
 .addConverterFactory(gsonFactory)B
 .build(); GsonConverterFactory.create()
  41. Converters GsonConverterFactory gsonFactory = GsonConverterFactory.create(); Retrofit retrofitFoo = new Retrofit.Builder()


    .baseUrl("http://foo.example.com")
 .addConverterFactory(gsonFactory)
 .build(); Retrofit retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com")
 .addConverterFactory(gsonFactory)
 .build();
  42. Converters Gson gson = new Gson(); GsonConverterFactory gsonFactory = GsonConverterFactory.create(gson);

    Retrofit retrofitFoo = new Retrofit.Builder()
 .baseUrl("http://foo.example.com")
 .addConverterFactory(gsonFactory)
 .build(); Retrofit retrofitBar = new Retrofit.Builder()
 .baseUrl("http://bar.example.com")
 .addConverterFactory(gsonFactory)
 .build();
  43. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .addConverterFactory(GsonConverterFactory.create())
 .build(); interface

    Service {
 @GET("/user")
 Call<User> user(); // <-- proto 
 @GET("/friends")
 Call<Friends> friends(); // <-- json
 }X
  44. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(ProtoConverterFactory.create())
 .addConverterFactory(GsonConverterFactory.create())
 .build();

    interface Service {
 @GET("/user")
 Call<User> user(); // <-- proto 
 @GET("/friends")
 Call<Friends> friends(); // <-- json
 }X
  45. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(ProtoConverterFactory.create()) User ?


    .addConverterFactory(GsonConverterFactory.create())
 .build(); interface Service {
 @GET("/user")
 Call<User> user(); 
 @GET("/friends")
 Call<Friends> friends();
 }X
  46. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(ProtoConverterFactory.create()) User ✓


    .addConverterFactory(GsonConverterFactory.create())
 .build(); interface Service {
 @GET("/user")
 Call<User> user(); 
 @GET("/friends")
 Call<Friends> friends();
 }X
  47. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(ProtoConverterFactory.create()) Friends ?


    .addConverterFactory(GsonConverterFactory.create())
 .build(); interface Service {
 @GET("/user")
 Call<User> user(); 
 @GET("/friends")
 Call<Friends> friends();
 }X
  48. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(ProtoConverterFactory.create()) Friends ✗


    .addConverterFactory(GsonConverterFactory.create())
 .build(); interface Service {
 @GET("/user")
 Call<User> user(); 
 @GET("/friends")
 Call<Friends> friends();
 }X
  49. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(ProtoConverterFactory.create()) Friends ✗


    .addConverterFactory(GsonConverterFactory.create()) 
 .build(); interface Service {
 @GET("/user")
 Call<User> user(); 
 @GET("/friends")
 Call<Friends> friends();
 }X
  50. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(ProtoConverterFactory.create()) Friends ✗


    .addConverterFactory(GsonConverterFactory.create()) Friends ?
 .build(); interface Service {
 @GET("/user")
 Call<User> user(); 
 @GET("/friends")
 Call<Friends> friends();
 }X
  51. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(ProtoConverterFactory.create()) Friends ✗


    .addConverterFactory(GsonConverterFactory.create()) Friends ✓
 .build(); interface Service {
 @GET("/user")
 Call<User> user(); 
 @GET("/friends")
 Call<Friends> friends();
 }X
  52. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(ProtoConverterFactory.create()) //

    No!
 .build(); interface Service {
 @GET("/user")
 Call<User> user(); 
 @GET("/friends")
 Call<Friends> friends();
 }X
  53. Converters interface Service {
 @GET("/user")
 Call<User> user(); // <-- xml

    
 @GET("/friends")
 Call<Friends> friends(); // <-- json
 }X
  54. Converters interface Service {
 @GET("/user")
 Call<User> user(); // <-- xml

    
 @GET("/friends")
 Call<Friends> friends(); // <-- json
 }X @interface Xml {}
  55. Converters interface Service {
 @GET("/user")
 Call<User> user(); // <-- xml

    
 @GET("/friends")
 Call<Friends> friends(); // <-- json
 }X @interface Xml {} @interface Json {}
  56. Converters interface Service {
 @GET("/user") @Xml
 Call<User> user(); // <--

    xml 
 @GET("/friends") @Json
 Call<Friends> friends(); // <-- json
 }X @interface Xml {} @interface Json {}
  57. Converters interface Service {
 @GET("/user") @Xml
 Call<User> user(); // <--

    xml 
 @GET("/friends") @Json
 Call<Friends> friends(); // <-- json
 }X @interface Xml {} @interface Json {}
  58. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(new XmlOrJsonConverterFactory())X
 .build();

    class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml = SimpleXmlConverterFactory.create(); }G
  59. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(new XmlOrJsonConverterFactory())X
 .build();

    class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml = SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); }G
  60. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(new XmlOrJsonConverterFactory())X
 .build();

    class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml = SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); @Override public Converter<ResponseBody, ?> responseBodyConverter() { }V }G
  61. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(new XmlOrJsonConverterFactory())X
 .build();

    class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml = SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); @Override public Converter<ResponseBody, ?> responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { }V }G
  62. Converters class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml =

    SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); @Override public Converter<ResponseBody, ?> responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { }V }G
  63. Converters class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml =

    SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); @Override public Converter<ResponseBody, ?> responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { }V }G
  64. Converters class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml =

    SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); @Override public Converter<ResponseBody, ?> responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { for (Annotation annotation : annotations) { }F }V }G
  65. Converters class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml =

    SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); @Override public Converter<ResponseBody, ?> responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { for (Annotation annotation : annotations) { if (annotation.getClass() == Xml.class) { }I }F }V }G
  66. Converters class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml =

    SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); @Override public Converter<ResponseBody, ?> responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { for (Annotation annotation : annotations) { if (annotation.getClass() == Xml.class) { return xml.responseBodyConverter(type, annotations, retrofit); }I }F }V }G
  67. Converters class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml =

    SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); @Override public Converter<ResponseBody, ?> responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { for (Annotation annotation : annotations) { if (annotation.getClass() == Xml.class) { return xml.responseBodyConverter(type, annotations, retrofit); }I if (annotation.getClass() == Json.class) { return json.responseBodyConverter(type, annotations, retrofit); }I }F }V }G
  68. Converters class XmlOrJsonConverterFactory implements Converter.Factory { final Converter.Factory xml =

    SimpleXmlConverterFactory.create(); final Converter.Factory json = GsonConverterFactory.create(); @Override public Converter<ResponseBody, ?> responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { for (Annotation annotation : annotations) { if (annotation.getClass() == Xml.class) { return xml.responseBodyConverter(type, annotations, retrofit); }I if (annotation.getClass() == Json.class) { return json.responseBodyConverter(type, annotations, retrofit); }I }F return null; }V }G
  69. Converters class AnnotatedConverterFactory implements Converter.Factory { final Map<Class<?>, Converter.Factory> factories;

    AnnotationConverterFactory(Map<Class<?>, Converter.Factory> factories) { this.factories = new LinkedHashMap<>(factories); } @Override public Converter<ResponseBody, ?> responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { for (Annotation annotation : annotations) { Converter.Factory factory = factories.get(annotation.getClass()); if (factory != null) { return factory.responseBodyConverter(type, annotations, retrofit); }I }F return null; }V }G
  70. Converters class AnnotatedConverterFactory implements Converter.Factory { // ... class Builder

    { final Map<Class<?>, Converter.Factory> factories = new LinkedHashMap<>(); Builder add(Class<? extends Annotation> cls, Converter.Factory factory) { if (cls == null) throw new NullPointerException("cls == null"); if (factory == null) throw new NullPointerException("factory == null"); factories.add(cls, factory); return this; } AnnotationConverterFactory build() { return new AnnotatedConverterFactory(factories); } }G
  71. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(AnnotatedConverterFactory.builder() .add(Xml.class, SimpleXmlConverterFactory.create())

    .add(Json.class, GsonConverterFactory.create()) .build())X
 .addConverterFactory(GsonConverterFactory.create())
 .build(); 
 new XmlOrJsonConverterFactory()
  72. Converters {Y "meta": { "code": 200, "time": 287, }, "notifications":

    {}, "response": {X "id": "1345235987", "name": "Shrek", "location": "Swamp" }X }Y
  73. Converters {Y "meta": { "code": 200, "time": 287, }, "notifications":

    {}, "response": {X "id": "1345235987", "name": "Shrek", "location": "Swamp" }X }Y
  74. Converters {Y "meta": { "code": 200, "time": 287, }, "notifications":

    {}, "response": {X "id": "1345235987", "name": "Shrek", "location": "Swamp" }X }Y
  75. Converters {Y "meta": { "code": 200, "time": 287, }, "notifications":

    {}, "response": {X "id": "1345235987", "name": "Shrek", "location": "Swamp" }X }Y
  76. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .addConverterFactory(GsonConverterFactory.create())
 .build(); interface

    Service {
 @GET("/user")
 Call<User> user();
 }X class Envelope<T> { Meta meta; List<Notification> notifications; T response; }Z
  77. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .addConverterFactory(GsonConverterFactory.create())
 .build(); interface

    Service {
 @GET("/user")
 Call<Envelope<User>> user();
 }X class Envelope<T> { Meta meta; List<Notification> notifications; T response; }Z
  78. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .addConverterFactory(GsonConverterFactory.create())
 .build(); interface

    Service {
 @GET("/user")
 Call<Envelope<User>> user();
 }X class Envelope<T> { Meta meta; List<Notification> notifications; T response; }Z
  79. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { }B }A
  80. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { }B }A
  81. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { }B }A
  82. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { }B }A
  83. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Type envelopedType = // Envelope.class parameterized with type }B }A
  84. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Type envelopedType = // Envelope.class parameterized with type TypeToken.getParameterized(Envelope.class, type).getType(); }B }A
  85. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Type envelopedType = // Envelope.class parameterized with type TypeToken.getParameterized(Envelope.class, type).getType(); Converter<ResponseBody, Envelope<?>> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); }B }A
  86. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Type envelopedType = // Envelope.class parameterized with type TypeToken.getParameterized(Envelope.class, type).getType(); Converter<ResponseBody, Envelope<?>> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return new Converter<ResponseBody, ?>() { }; }B }A
  87. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Type envelopedType = // Envelope.class parameterized with type TypeToken.getParameterized(Envelope.class, type).getType(); Converter<ResponseBody, Envelope<?>> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return new Converter<ResponseBody, ?>() { @Override public Object convert(ResponseBody body) { } }; }B }A
  88. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Type envelopedType = // Envelope.class parameterized with type TypeToken.getParameterized(Envelope.class, type).getType(); final Converter<ResponseBody, Envelope<?>> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return new Converter<ResponseBody, ?>() { @Override public Object convert(ResponseBody body) { Envelope<?> envelope = delegate.convert(body); }B }; }B }A
  89. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Type envelopedType = // Envelope.class parameterized with type TypeToken.getParameterized(Envelope.class, type).getType(); final Converter<ResponseBody, Envelope<?>> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return new Converter<ResponseBody, ?>() { @Override public Object convert(ResponseBody body) { Envelope<?> envelope = delegate.convert(body); return envelope.response; }B }; }B }A
  90. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .addConverterFactory(GsonConverterFactory.create())
 .build(); interface

    Service {
 @GET("/user")
 Call<Envelope<User>> user();
 }X class Envelope<T> { Meta meta; List<Notification> notifications; T response; }Z
  91. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(new EnvelopingConverter())
 .addConverterFactory(GsonConverterFactory.create())


    .build(); interface Service {
 @GET("/user")
 Call<Envelope<User>> user();
 }X class Envelope<T> { Meta meta; List<Notification> notifications; T response; }Z
  92. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(new EnvelopingConverter())
 .addConverterFactory(GsonConverterFactory.create())


    .build(); interface Service {
 @GET("/user")
 Call<User> user();
 }X class Envelope<T> { Meta meta; List<Notification> notifications; T response; }Z
  93. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(new EnvelopingConverter())
 .addConverterFactory(GsonConverterFactory.create())


    .build(); interface Service {
 @GET("/user")
 Call<User> user();
 }X class Envelope<T> { Meta meta; List<Notification> notifications; T response; }Z
  94. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Type envelopedType = // Envelope.class parameterized with type TypeToken.getParameterized(Envelope.class, type).getType(); final Converter<ResponseBody, Envelope<?>> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return new Converter<ResponseBody, ?>() { @Override public Object convert(ResponseBody body) { Envelope<?> envelope = delegate.convert(body); return envelope.response; }B }; }B }A
  95. Converters class EnvelopingConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Type envelopedType = // Envelope.class parameterized with type TypeToken.getParameterized(Envelope.class, type).getType(); final Converter<ResponseBody, Envelope<?>> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return new Converter<ResponseBody, ?>() { @Override public Object convert(ResponseBody body) { Envelope<?> envelope = delegate.convert(body); // Handle notifications, record timing information. return envelope.response; }B }; }B }A
  96. Converters class EmptyToNullConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { }B }A
  97. Converters class EmptyToNullConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); }B }A
  98. Converters class EmptyToNullConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return new Converter<ResponseBody, ?>() { @Override public Object convert(ResponseBody body) { }G }; }B }A
  99. Converters class EmptyToNullConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return new Converter<ResponseBody, ?>() { @Override public Object convert(ResponseBody body) { if (body.contentLength() == 0) return null; }G }; }B }A
  100. Converters class EmptyToNullConverter implements Converter.Factory { @Override public Converter<ResponseBody, ?>

    responseBodyConverter( Type type, Annotation[] annotations, Retrofit retrofit) { final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return new Converter<ResponseBody, ?>() { @Override public Object convert(ResponseBody body) { if (body.contentLength() == 0) return null; return delegate.convert(body); }G }; }B }A
  101. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(new EnvelopingConverter())
 .addConverterFactory(GsonConverterFactory.create())


    .build(); interface Service {
 @GET("/user")
 Call<User> user();
 }X class Envelope<T> { Meta meta; List<Notification> notifications; T response; }Z
  102. Converters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addConverterFactory(new EmptyToNullConverter()) .addConverterFactory(new

    EnvelopingConverter())
 .addConverterFactory(GsonConverterFactory.create())
 .build(); interface Service {
 @GET("/user")
 Call<User> user();
 }X class Envelope<T> { Meta meta; List<Notification> notifications; T response; }Z
  103. Converters interface DribbbleSearchService { @GET("search") Call<List<Shot>> search(@Query("q") String query, @Query("page")

    Integer page, @Query("per_page") Integer pageSize, @Query("s") @SortOrder String sort); }
  104. Converters interface DribbbleSearchService { @GET("search") Call<List<Shot>> search(@Query("q") String query, @Query("page")

    Integer page, @Query("per_page") Integer pageSize, @Query("s") @SortOrder String sort); }
  105. Converters /** * Dribbble API does not have a search

    endpoint so we have * to do gross things :( */ class DribbbleSearchConverter { // ... }
  106. Converters /** * Dribbble API does not have a search

    endpoint so we have * to do gross things :( */ class DribbbleSearchConverter { // ... }
  107. Converters /** * Dribbble API does not have a search

    endpoint so we have * to do gross things :( */ class DribbbleSearchConverter { // ... } http://jakes.link/plaid-converter
  108. Call Adapters interface Service {
 @GET("/user")
 Call<User> user();
 }X Call<User>

    Call<User> Call Call.Factory (aka OkHttpClient) CallAdapter
  109. Call Adapters interface Service {
 @GET("/user")
 Call<User> user();
 }X Call<User>

    Call<User> Call Call.Factory (aka OkHttpClient) CallAdapter
  110. Call Adapters interface Service {
 @GET("/user")
 Call<User> user();
 }X Call<User>

    Call<User> Call Call.Factory (aka OkHttpClient) CallAdapter
  111. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 .build();

    interface Service {
 @GET("/user")
 Observable<User> user();
 }X Observable<User> Call<User> Call Call.Factory (aka OkHttpClient) CallAdapter
  112. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 .build();

    interface Service {
 @GET("/user")
 Observable<User> user();
 }X Observable<User> Call<User> Call Call.Factory (aka OkHttpClient) CallAdapter
  113. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 .build();

    interface Service {
 @GET("/user")
 Observable<User> user();
 }X Observable<User> Call<User> Call Call.Factory (aka OkHttpClient) CallAdapter
  114. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 .build();

    interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  115. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addCallAdapterFactory(new

    BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  116. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addCallAdapterFactory(new

    BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  117. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addCallAdapterFactory(new

    BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  118. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) ?

    .addCallAdapterFactory(new BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  119. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) ✓

    .addCallAdapterFactory(new BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  120. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addCallAdapterFactory(new

    BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  121. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addCallAdapterFactory(new

    BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  122. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addCallAdapterFactory(new

    BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  123. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) ?

    .addCallAdapterFactory(new BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  124. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) ✗

    .addCallAdapterFactory(new BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  125. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) ✗

    .addCallAdapterFactory(new BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  126. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) ✗

    .addCallAdapterFactory(new BuiltInCallFactory()) // implict! ?
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  127. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) ✗

    .addCallAdapterFactory(new BuiltInCallFactory()) // implict! ✓
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  128. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addCallAdapterFactory(new

    BuiltInCallFactory()) // implict!
 .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  129. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 .build();

    interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends();
 }X
  130. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addCallAdapterFactory(Java8CallAdapterFactory.create())


    .build(); interface Service {
 @GET("/user")
 Observable<User> user(); @GET("/friends") Call<List<User>> friends(); @GET("/enemies") CompletableFuture<List<User>> enemies();
 }X
  131. Call Adapters class RxObserveOnCallAdapterFactory extends CallAdapter.Factory { @Override public CallAdapter<?,

    ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { }B }A
  132. Call Adapters class RxObserveOnCallAdapterFactory extends CallAdapter.Factory { @Override public CallAdapter<?,

    ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Observable.class) { return null; }C }B }A
  133. Call Adapters class RxObserveOnCallAdapterFactory extends CallAdapter.Factory { @Override public CallAdapter<?,

    ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Observable.class) { return null; }C CallAdapter<Object, Observable<?>> delegate = retrofit.nextCallAdapter(returnType, annotations); }B }A
  134. Call Adapters class RxObserveOnCallAdapterFactory extends CallAdapter.Factory { @Override public CallAdapter<?,

    ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Observable.class) { return null; }C CallAdapter<Object, Observable<?>> delegate = retrofit.nextCallAdapter(returnType, annotations); return new CallAdapter<Observable<?>>() { @Override public Observable<?> adapt(Call<Object> call) { }E }D }B }A
  135. Call Adapters class RxObserveOnCallAdapterFactory extends CallAdapter.Factory { @Override public CallAdapter<?,

    ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Observable.class) { return null; }C CallAdapter<Object, Observable<?>> delegate = retrofit.nextCallAdapter(returnType, annotations); return new CallAdapter<Observable<?>>() { @Override public Observable<?> adapt(Call<Object> call) { Observable<?> o = delegate.adapt(call); }E }D }B }A
  136. Call Adapters class RxObserveOnCallAdapterFactory extends CallAdapter.Factory { @Override public CallAdapter<?,

    ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Observable.class) { return null; }C CallAdapter<Object, Observable<?>> delegate = retrofit.nextCallAdapter(returnType, annotations); return new CallAdapter<Observable<?>>() { @Override public Observable<?> adapt(Call<Object> call) { Observable<?> o = delegate.adapt(call); return o.observeOn(mainThread()); }E }D }B }A
  137. Call Adapters class RxObserveOnCallAdapterFactory extends CallAdapter.Factory { @Override public CallAdapter<?,

    ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != Observable.class) { return null; }C CallAdapter<Object, Observable<?>> delegate = retrofit.nextCallAdapter(returnType, annotations); return new CallAdapter<Observable<?>>() { @Override public Observable<?> adapt(Call<Object> call) { Observable<?> o = delegate.adapt(call); return o.observeOn(mainThread()); }E @Override public Type responseType() { return delegate.responseType(); } }D }B }A
  138. Call Adapters Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com") .addCallAdapterFactory(new RxObserveOnCallAdapterFactory())

    .addCallAdapterFactory( RxJavaCallAdapterFactory.createWithScheduler(io()))
 .build(); interface Service {
 @GET("/user")
 Observable<User> user();
 }X
  139. Call Adapters interface Service {
 @GET("/user")
 Call<User> user();
 }X Response<User>

    response = call.execute(); // or enqueue() if (!response.isSuccessful()) { // handle error body? }
  140. Call Adapters interface Service {
 @GET("/user")
 Call<User> user();
 }X Response<User>

    response = call.execute(); // or enqueue() if (!response.isSuccessful()) { ResponseBody errorBody = response.errorBody(); }
  141. Call Adapters interface Call<R, E> { Response<R, E> execute(); void

    enqueue(Callback<R, E> cb); } interface Callback<R, E> { void onResponse(Response<R, E> response); void onFailure(IOException e); } interface Response<R, E> { R body(); E error(); }
  142. Call Adapters interface Call<R, E> { Response<R, E> execute(); void

    enqueue(Callback<R, E> cb); } interface Callback<R, E> { void onResponse(Response<R, E> response); void onFailure(IOException e); } interface Response<R, E> { R body(); E error(); }
  143. Call Adapters interface Call<R, E> { Response<R, E> execute(); void

    enqueue(Callback<R, E> cb); }1 interface Callback<R, E> { void onResponse(Response<R, E> response);A void onFailure(IOException e); }2 interface Response<R, E> { R body(); E error(); }3
  144. Call Adapters interface Call<R, E> { Response<R, E> execute(); void

    enqueue(Callback<R, E> cb); }1 interface Callback<R, E> { void onSuccess(R body);A void onError(E errorBody); void onFailure(IOException e); }2 Response Response< , > response interface Response<R, E> { R body(); E error(); }3
  145. Call Adapters interface Call<R, E> { Response<R, E> execute(); void

    enqueue(Callback<R, E> cb); }1 interface Callback<R, E> { void onSuccess(R body);A void onClientError(E errorBody); void onServerError(String message); void onUnauthenticated(); void onFailure(IOException e); }2
  146. Mock Mode interface Service {
 @GET("/user")
 Call<User> user();
 }X Service

    service = retrofit.create(Service.class); class MockService implements Service { @Override public Call<List<User>> user() { return Calls.success( Arrays.asList(new User("Alice"), new User("Bob"))); } }
  147. Mock Mode interface Service {
 @GET("/user")
 Call<User> user();
 }X Service

    service = retrofit.create(Service.class); class MockService implements Service { @Override public Call<List<User>> user() { return Calls.success( Arrays.asList(new User("Alice"), new User("Bob"))); }B }A Service fakeService = new MockService();
  148. Mock Mode class MockService implements Service { @Override public Call<List<User>>

    user() { return Calls.success( Arrays.asList(new User("Alice"), new User("Bob"))); }B }A
  149. Mock Mode class MockService implements Service { final BehaviorDelegate<Service> delegate;

    MockService(BehaviorDelegate<Service> delegate) { this.delegate = delegate; }C @Override public Call<List<User>> user() { return Calls.success( Arrays.asList(new User("Alice"), new User("Bob")));Z }B }A
  150. Mock Mode class MockService implements Service { final BehaviorDelegate<Service> delegate;

    MockService(BehaviorDelegate<Service> delegate) { this.delegate = delegate; }C @Override public Call<List<User>> user() { List<User> response = Arrays.asList(new User("Alice"), new User("Bob"));Z return delegate.returningResponse(response).user(); }B }A Calls.success( )
  151. Mock Mode Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .build(); NetworkBehavior

    behavior = NetworkBehavior.create(); MockRetrofit mockRetrofit = new MockRetrofit.Builder() .networkBehavior(behavior) .build();
  152. Mock Mode Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .build(); NetworkBehavior

    behavior = NetworkBehavior.create(); MockRetrofit mockRetrofit = new MockRetrofit.Builder() .networkBehavior(behavior) .build(); BehaviorDelegate<Service> delegate = mockRetrofit.create(Service.class);
  153. Mock Mode Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .build(); NetworkBehavior

    behavior = NetworkBehavior.create(); MockRetrofit mockRetrofit = new MockRetrofit.Builder() .networkBehavior(behavior) .build(); BehaviorDelegate<Service> delegate = mockRetrofit.create(Service.class); Service mockService = new MockService(delegate);
  154. Mock Mode Retrofit retrofit = new Retrofit.Builder()
 .baseUrl("http://example.com")
 .build(); NetworkBehavior

    behavior = NetworkBehavior.create(); MockRetrofit mockRetrofit = new MockRetrofit.Builder() .networkBehavior(behavior) .build(); BehaviorDelegate<Service> delegate = mockRetrofit.create(Service.class); Service mockService = new MockService(delegate);
  155. Retrofit • HTTP client sends the bits across the wire.

    • Converters manipulate request/response data.
  156. Retrofit • HTTP client sends the bits across the wire.

    • Converters manipulate request/response data. • Call adapters change execution mechanism.
  157. Retrofit • HTTP client sends the bits across the wire.

    • Converters manipulate request/response data. • Call adapters change execution mechanism. • Mock mode fakes your server behavior locally.