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 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