Written by Adrian Kremski
Android Developer
Published October 8, 2015

Retrofit 2.0: what’s new?

Retrofit is a HTTP client library for Android created by Square. In this post we will cover the new version of Retrofit introduced by Jack Wharton during Droidcon NYC 2015 and what has changed in it.

For purpose of presenting Retrofit 2.0 functions we are going to work with API created on apiary.io platform.

Let’s get down to business!

1. Setup

First, we will add a few dependencies to our gradle.build to fetch Retrofit and corresponding tools.

Retrofit 2.0 beta

dependencies {
    compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
}

Gson converter

dependencies {
    compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
    compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
}

In Retrofit 1.9, GsonConverter was a default option for the RestAdapter but from now on the converters need to be plugged in manually.

Other converters

dependencies {
    compile 'com.squareup.retrofit:converter-jackson:2.0.0-beta2'
    compile 'com.squareup.retrofit:converter-moshi:2.0.0-beta2'
    compile 'com.squareup.retrofit:converter-protobuf:2.0.0-beta2'
    compile 'com.squareup.retrofit:converter-wire:2.0.0-beta2'
    compile 'com.squareup.retrofit:converter-simplexml:2.0.0-beta2'
}

2. API

After gradle setup, let’s dig into the API with which we are going to communicate.

Our “backend” serves 3 urls

[GET] http://private-1ab0-adriankremski.apiary-mock.com/notes for fetching notes

[POST] http://private-1ab0-adriankremski.apiary-mock.com/notes for creating new notes

[GET] http://private-1ab0-adriankremski.apiary-mock.com/notes/{id}

Now that we know, what our resource looks like we can define the Note model in Java

public class Note {
   public long id;
   public String title;
}

Pretty simple, isn’t it ?

3. NotesService

All API endpoints must be mapped to a corresponding interfaces in Java, so let’s do this

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public interface NotesService {
@GET("/notes")
Call<List> notes();
@GET("/notes")
Call<Note> createNote(@Body Note note);
@GET("/notes/{id}")
Call<Note> note();
}
public interface NotesService { @GET("/notes") Call<List> notes(); @GET("/notes") Call<Note> createNote(@Body Note note); @GET("/notes/{id}") Call<Note> note(); }
public interface NotesService {
   @GET("/notes")
   Call<List> notes();

   @GET("/notes")
   Call<Note> createNote(@Body Note note);

   @GET("/notes/{id}")
   Call<Note> note();
}

Retrofit 2.0 introduced a new Call class (it also exists in OkHttp package).

Screen Shot 2015-10-06 at 15.44.27

(screen is taken from Jack Whartons presentation during Droidcon NYC 2015, available here)

Similar endpoints that can be defined in Java with Retrofit

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public interface NotesService {
@GET("notes")
Call<List<Note>> notes(@QueryMap Map queryMap);
// notesService.notes(Collections.singletonMap("type", "latest"));
// http://private-1ab0-adriankremski.apiary-mock.com/notes?type=latest
@GET("notes")
Call<List<Note>> notes(@Query(“type”) String typeQuery);
// notesService.notes(“type”);
// http://private-1ab0-adriankremski.apiary-mock.com/notes?type=latest
@DELETE("notes/{id}")
Call<Void> deleteNote(@Path("id") String id);
@Headers({"Accept: application/json"})
@PUT("notes/{id}")
Call<Note> updateNote(@Path("id") String id, @Body Note note);
@GET("http://private-1ab0-adriankremski.apiary-mock.com/notes")
Call<List<Note>> notesFull();
@FormUrlEncoded
@PUT("/notes/{id}")
Call<Note> updateNote(@Path("id") String id, @Field("title") String title);
@Multipart
@PUT("/notes/{id}/photo")
Call<Note> updateNote(@Path("id") String id, @Part("photo") RequestBody photo);
}
public interface NotesService { @GET("notes") Call<List<Note>> notes(@QueryMap Map queryMap); // notesService.notes(Collections.singletonMap("type", "latest")); // http://private-1ab0-adriankremski.apiary-mock.com/notes?type=latest @GET("notes") Call<List<Note>> notes(@Query(“type”) String typeQuery); // notesService.notes(“type”); // http://private-1ab0-adriankremski.apiary-mock.com/notes?type=latest @DELETE("notes/{id}") Call<Void> deleteNote(@Path("id") String id); @Headers({"Accept: application/json"}) @PUT("notes/{id}") Call<Note> updateNote(@Path("id") String id, @Body Note note); @GET("http://private-1ab0-adriankremski.apiary-mock.com/notes") Call<List<Note>> notesFull(); @FormUrlEncoded @PUT("/notes/{id}") Call<Note> updateNote(@Path("id") String id, @Field("title") String title); @Multipart @PUT("/notes/{id}/photo") Call<Note> updateNote(@Path("id") String id, @Part("photo") RequestBody photo); }
public interface NotesService {
  
@GET("notes")
Call<List<Note>> notes(@QueryMap Map queryMap);
// notesService.notes(Collections.singletonMap("type", "latest"));
// http://private-1ab0-adriankremski.apiary-mock.com/notes?type=latest

@GET("notes")
Call<List<Note>> notes(@Query(“type”) String typeQuery);
// notesService.notes(“type”);
// http://private-1ab0-adriankremski.apiary-mock.com/notes?type=latest

@DELETE("notes/{id}")
Call<Void> deleteNote(@Path("id") String id);

@Headers({"Accept: application/json"})
@PUT("notes/{id}")
Call<Note> updateNote(@Path("id") String id, @Body Note note);

@GET("http://private-1ab0-adriankremski.apiary-mock.com/notes")
Call<List<Note>> notesFull();

@FormUrlEncoded
@PUT("/notes/{id}")
Call<Note> updateNote(@Path("id") String id, @Field("title") String title);

@Multipart
@PUT("/notes/{id}/photo")
Call<Note> updateNote(@Path("id") String id, @Part("photo") RequestBody photo);

}

After defining the NotesService we can finally make some requests.
To do that we will use the Retrofit class (in 1.9 it’s called RestAdapter) to instantiate our NotesService.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
String baseUrl = "http://private-1ab0-adriankremski.apiary-mock.com";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
final NotesService service = retrofit.create(NotesService.class);
String baseUrl = "http://private-1ab0-adriankremski.apiary-mock.com"; Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .build(); final NotesService service = retrofit.create(NotesService.class);
    String baseUrl = "http://private-1ab0-adriankremski.apiary-mock.com";
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    final NotesService service = retrofit.create(NotesService.class);

Now we have two options to do HTTP calls.

Synchronous and asynchronous

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
final NotesService service = retrofit.create(NotesService.class);
Response<List<Note>> notes = service.notes().execute();
// Synchronous call. It will throw NetworkOnMainThreadException when called on main thread
Call<List<Note>> notesCall = service.notes();
notesCall.enqueue(new Callback<List<Note>>() {
@Override
public void onResponse(Response<List<Note>> response, Retrofit retrofit) {
}
@Override
public void onFailure(Throwable t) {
}
});
// Asynchronous call
final NotesService service = retrofit.create(NotesService.class); Response<List<Note>> notes = service.notes().execute(); // Synchronous call. It will throw NetworkOnMainThreadException when called on main thread Call<List<Note>> notesCall = service.notes(); notesCall.enqueue(new Callback<List<Note>>() { @Override public void onResponse(Response<List<Note>> response, Retrofit retrofit) { } @Override public void onFailure(Throwable t) { } }); // Asynchronous call
    final NotesService service = retrofit.create(NotesService.class);

    Response<List<Note>> notes = service.notes().execute();
    // Synchronous call. It will throw NetworkOnMainThreadException when called on main thread

    Call<List<Note>> notesCall = service.notes();

    notesCall.enqueue(new Callback<List<Note>>() {
        @Override
        public void onResponse(Response<List<Note>> response, Retrofit retrofit) {

        }

        @Override
        public void onFailure(Throwable t) {

        }
    });
    // Asynchronous call

As you can see we have two methods to handle here: onResponse and onFailure.

If the request is successful, onResponse method is called with the response encapsulated in the response variable. In case of a failure, both methods are invoked, (response.body() will return as null but you can retrieve the error body from response.errorBody()).

Overview of the Response class

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Response {
int code(); // HTTP code (200,404, etc)
String message(); // OK for success
Headers headers(); // headers of HTTP call
boolean isSuccess();
T body(); // main response content (can be parsed into a java model)
ResponseBody errorBody(); // error message
com.squareup.okhttp.Response raw(); // raw response message
}
class Response { int code(); // HTTP code (200,404, etc) String message(); // OK for success Headers headers(); // headers of HTTP call boolean isSuccess(); T body(); // main response content (can be parsed into a java model) ResponseBody errorBody(); // error message com.squareup.okhttp.Response raw(); // raw response message }
class Response {
        int code(); // HTTP code (200,404, etc)
        String message(); // OK for success
        Headers headers(); // headers of HTTP call
        boolean isSuccess();
        T body(); // main response content (can be parsed into a java model)
        ResponseBody errorBody(); // error message
        com.squareup.okhttp.Response raw(); // raw response message
    }

Remember that each Call instance can be invoked only once. Otherwise it will throw an exception

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Call<List<Note>> notesCall = service.notes();
notesCall.execute();
notesCall.execute(); // raises IllegallStateException
Call<List<Note>> notesCall = service.notes(); notesCall.execute(); notesCall.execute(); // raises IllegallStateException
    Call<List<Note>> notesCall = service.notes();

    notesCall.execute();

    notesCall.execute(); // raises IllegallStateException

If we want to retry the call, we can clone it and then execute

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Call<List<Note>> notesCall = service.notes();
notesCall.execute();
notesCall.clone().execute();
Call<List<Note>> notesCall = service.notes(); notesCall.execute(); notesCall.clone().execute();
    Call<List<Note>> notesCall = service.notes();

    notesCall.execute();

    notesCall.clone().execute();

4. Integrating RxJava

Retrofit 1.9 allowed developers to use RxJava for requests invocation. In v2.0 it’s still possible, however it requires some extra steps.

To integrate it, we need a custom CallAdapter mechanism (already available in Retrofit)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
compile 'io.reactivex:rxandroid:1.0.1'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1' compile 'io.reactivex:rxandroid:1.0.1'
    compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
    compile 'io.reactivex:rxandroid:1.0.1'

Updating retrofit instance

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
String baseUrl = "http://private-1ab0-adriankremski.apiary-mock.com";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
final NotesService service = retrofit.create(NotesService.class);
String baseUrl = "http://private-1ab0-adriankremski.apiary-mock.com"; Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); final NotesService service = retrofit.create(NotesService.class);
    String baseUrl = "http://private-1ab0-adriankremski.apiary-mock.com";
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .build();

    final NotesService service = retrofit.create(NotesService.class);

Finally, we are ready to integrate Observables with our NotesService

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public interface NotesService {
@GET("notes")
Observable<List<Note>> notes();
@GET("notes")
Observable<Note> createNote(@Body Note note);
@GET("notes/{id}")
Observable<Note> note();
}
public interface NotesService { @GET("notes") Observable<List<Note>> notes(); @GET("notes") Observable<Note> createNote(@Body Note note); @GET("notes/{id}") Observable<Note> note(); }
    public interface NotesService {

    @GET("notes")
    Observable<List<Note>> notes();

    @GET("notes")
    Observable<Note> createNote(@Body Note note);

    @GET("notes/{id}")
    Observable<Note> note();
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Observable<List<Note>> observable = service.notes();
observable.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Note>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List<Note> notes) {
}
});
Observable<List<Note>> observable = service.notes(); observable.observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<List<Note>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(List<Note> notes) { } });
    Observable<List<Note>> observable = service.notes();

    observable.observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<List<Note>>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
            }

            @Override
            public void onNext(List<Note> notes) {
            }
    });

5. Final note

For more changes, please check the Changelog of Retrofit 2.0 and official documentation available  here

Written by Adrian Kremski
Android Developer
Published October 8, 2015