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

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

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.

    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

    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

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

    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

    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)

    compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
    compile 'io.reactivex:rxandroid:1.0.1'

Updating retrofit instance

    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

    public interface NotesService {

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

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

    @GET("notes/{id}")
    Observable<Note> note();
}
    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