Skip to content

Use Retrofit to Handle REST Apis in your android app

rutura edited this page Apr 27, 2017 · 4 revisions
  • Retrofit makes the job of downloading JSON and XML data from the server easy. In GSON Guide GSON could help us parse JSON responses but we still had to do our own http requests and to some extend mess with how JSON is turned into POJOs we can directly use in your app.Retrofit can abstract all that hussle from you and you can focus on the shiny things in your app.

  • The first thing is probably to take care of the dependencies:

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-moshi:2.1.0'
compile 'com.android.support:appcompat-v7:25.3.1'
compile "com.android.support:design:25.3.1"
compile "com.android.support:recyclerview-v7:25.3.1"
compile "com.android.support:cardview-v7:25.3.1"
  • We will be fetching JSON data from the JSONPlaceholder service and particularly the posts.And the response we will be getting is of the form :
[
  {
    "userId": 1,
    "id": 1,
    "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
  },
  {
    "userId": 1,
    "id": 2,
    "title": "qui est esse",
    "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
  },
  {
    "userId": 1,
    "id": 3,
    "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
    "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
  },
  {
    "userId": 1,
    "id": 4,
    "title": "eum et est occaecati",
    "body": "ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit"
  },
  {
    "userId": 1,
    "id": 5,
    "title": "nesciunt quas odio",
    "body": "repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque"
  }
]

This gives us a good idea about the fields one post will contain, mainly: userId, id, title and body.

  • We can now design our Java class to match to one post:
public class Post implements Parcelable {
    public Long id;
    public Long userId;
    public String title;
    public String body;

    protected Post(Parcel in) {
        id = in.readLong();
        userId = in.readLong();
        title = in.readString();
        body = in.readString();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeLong(id);
        dest.writeLong(userId);
        dest.writeString(title);
        dest.writeString(body);
    }

    public static final Parcelable.Creator<Post> CREATOR = new Parcelable.Creator<Post>() {
        @Override
        public Post createFromParcel(Parcel in) {
            return new Post(in);
        }

        @Override
        public Post[] newArray(int size) {
            return new Post[size];
        }
    };

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Post post = (Post) o;

        return id != null ? id.equals(post.id) : post.id == null;

    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }
}
  • The most important thing to notice in this Post class is that it defines the fields that are named exactly the same as in the JSON response we got from the server. These fields should be exactly like that.
    public Long id;
    public Long userId;
    public String title;
    public String body;
  • The Parcelable interface and all the other methods are here just to allow us to save and load the data between configuration changes so we don't have to perform other network queries.You can ignore that for now if it confuses you.

  • Next, we define a Java equivalent of the REST service for use in Retrofit. In your Java/Android code you will basically call the methods exposed by this interface. Let's see it first and then try to explain its mechanics:

 public interface PostsService {
    @GET("posts")
    Call<List<Post>> getPosts();

    @GET("posts")
    Call<List<Post>> getPosts(@Query("userId") Long userId);

    @POST("posts")
    Call<Post> createPost(@Body Post post);

    @PUT("posts/{id}")
    Call<Post> updatePost(@Path("id") Long id, @Body Post post);

    @DELETE("posts/{id}")
    Call<Void> deletePost(@Path("id") Long id);
}
  • Each method in our interface is annotated with @GET, @POST, @PUT or @DELETE, depending on the HTTP method used in that case.
  • Each annotation contains the path (without a / prefix) that maps to the request path.For example consider the full request url shown below :
http://jsonplaceholder.typicode.com/posts

the left part

http://jsonplaceholder.typicode.com/

is our base url and

posts 

is our path

  • When a certain HTTP method and path requires query parameters, we can add arguments in the method definition that is annotated with @Query, as shown in the second method called getPosts().

  • When the request path is dynamic, such as the preceding example when the id for a post is contained in the path, we can add that as a parameter in the @GET, @POST, @PUT or @DELETE annotation using curly braces and then add a method parameter with the same id.

  • The return value from the methods in our interface is always of type Call, with the generic type representing the response, such as Call when a single object is returned. If the request will return a JSON array with objects, the return value would be Call<List>.

  • Now all the building blocks are in place. Next we need to perform network requests. These are usually performed as responses to click events or some other event in our app.

  • Because we want to fetch all the posts in our app , we implement the Callback<List> interface in our activity.This interface is exposed internaly by Retrofit and it has two override methods : onResponse() which is triggered when the request has been a success and onFailure() triggered when there has been some error.

public class MainActivity extends AppCompatActivity implements Callback<List<Post>> {
   
    private static final String REST_API_BASEURL = "http://jsonplaceholder.typicode.com/";
    private PostsService postsService;
    private Call<List<Post>> listCall;//Use this to send requests to the server
    ...
  • postService is used when we create our retrofit instance :
Retrofit retrofit = new Retrofit.Builder()
     .baseUrl(REST_API_BASEURL)
     .addConverterFactory(MoshiConverterFactory.create())
     .build();
     postsService = retrofit.create(PostsService.class);
  • listCall is used to trigger the network request:
public void doRefresh(MenuItem item) {
        if (listCall == null) {
            listCall = postsService.getPosts();
            listCall.enqueue(this);
        } else {
            listCall.cancel();
            listCall = null;
        }
    }
  • After the request is triggered, you get the response in one of the Callback<List> overrides:
@Override
    public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
        if (response.isSuccessful()) {
            posts = response.body();
            postAdapter.notifyDataSetChanged();
        }
        listCall = null;
    }



    @Override
    public void onFailure(Call<List<Post>> call, Throwable t) {
        Toast.makeText(this, "Failed to fetch posts!", Toast.LENGTH_SHORT).show();
        listCall = null;
    }

The code loads posts data in the adapter of the RecyclerView for them to be shown on success and simply show a Toast error message when something goes wrong.

Clone this wiki locally