Retrofit – Diving in!

Retrofit – Diving in!

Hello friends! Sorry for not posting any update for about 2 weeks. It was a silly mistake to give blogging a break.

Today I want to share a small tutorial about Retrofit with you.

Retrofit is a type-safe HTTP client for Android and Java.

make This statement simply means that Retrofit is a framework for Android and Java to make network requests(GET/POST) without any need of knowing low level network details.

To make use of Retrofit services you have to create some endpoints for fetching of data from a Web API. In this particular tutorial I will be using GitHub API to fetch the names of all the repositories of a particular username.

So lets get started.

Required Java and XML files-

To get up and running with this Retrofit tutorial, you will need following Java files.

// GitHubRepo.java

// Class representing a GitHub repo and its behaviour is get
// a repo's name

public class GitHubRepo {
    private String name;
    public String getName() {
        return name;
    }
}
// GitHubRepoAdapter.java

// A custom adapter to get github repos from the data source

public class GitHubRepoAdapter extends ArrayAdapter<GitHubRepo> {
    public GitHubRepoAdapter(Activity context, List<GitHubRepo> repos) {
        super(context, 0, repos);
    }

    @Override
    public View getView(int position, View view, ViewGroup viewGroup) {
        if(view == null){
            view = LayoutInflater.from(getContext())
                                 .inflate(R.layout.list_content_layout, viewGroup, false);
        }

        GitHubRepo currentGitHubRepo = getItem(position);

        TextView nameOfRepo = (TextView) view.findViewById(R.id.repo_name);
        nameOfRepo.setText(currentGitHubRepo.getName());
        return view;
    }

}
// activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" />
// list_content_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/repo_name"/>
</LinearLayout>

Step 1) Adding gradle dependencies and network permissions.

First of all to use Retrofit in an existing or a new Android Project, you will have to add Gradle dependencies in the gradle.build(Module: app) and add network permissions in the AndroidManifest.xml file by adding following lines of code-

// ADD THESE LINES IN gradle.build file
// Retrofit & OkHttp
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.android.support:appcompat-v7:25.2.0'
testCompile 'junit:junit:4.12'
// ADD THIS LINE IN AndroidManifest.xml file
<uses-permission android:name="android.permission.INTERNET" />

Step 2) Describe API endpoints

API endpoint simply means the URL from which you want to fetch your desired data. Every API endpoint have two parts, first is the base URL and another is the query for fetching data from a particular dataset. To add an API endpoint for fetching all the repos by a particular username, you will have to create an interface which will act as a medium for our app to interact with the API using Retrofit.

Lets say the name of the Interface here is GitHubClient.

public interface GitHubClient {

    @GET("/users/cocos/repos")
    List<GitHubRepo> reposForUser(String user);
}

This above code may seem alien to you but frankly speaking I felt the same way about it a few hours ago.

In Retrofit we use Annotations to specify the type of network request we want to make and the parameter for the annotations specify the query for the API. Here ‘cocos’ is the username whose repos we want to fetch from the GitHub server. This is a good code as we have hard coded the name of the user but instead we can generalise this code to fetch data from any username we enter and not just from ‘cocos’. To do so we use following code,

public interface GitHubClient {

    @GET("/users/{user}/repos")
    List<GitHubRepo> reposForUser(@Path("user") String user);
}

The ‘{user}’ here is a Retrofit’s feature and called as Path parameters. I will cover Path parameters in details in a different blogpost. Whenever we use reposForUser() method and pass a username as argument it replaces ‘{user}’ from the get parameter.

Now the code looks complete but there is still a thing you should know about it. The about code is synchronous, that means the network request that it will make will be on Main thread and making network requests on Main thread is something that every Android programmer avoids. To make this async we will use another Retrofit feature called Wrapping in Call object. In this we wrap the network call in a Call object and Retrofit hides all the technicality of async network call. Isn’t it cool?

So now the code will look like this,

public interface GitHubClient {

    @GET("/users/{user}/repos")
    Call<List<GitHubRepo>> reposForUser(@Path("user") String user);
}

Step 3) Fetching data and bind it with MainActivity

To get the desired list of repos, our MainActivity.java file should look as follows,

// MainActivity.java
public class MainActivity extends AppCompatActivity {

    private ListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView = (ListView)findViewById(R.id.listview);
        // ******************************************************
        Retrofit.Builder builder = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create());
     
        Retrofit retrofit = builder.build();
        
        GitHubClient client = retrofit.create(GitHubClient.class);

        Call<List<GitHubRepo>> call = client.reposForUser("django");

        call.enqueue(new Callback<List<GitHubRepo>>() {
            @Override
            public void onResponse(Call<List<GitHubRepo>> call, Response<List<GitHubRepo>> response) {
                List<GitHubRepo> repos = response.body();
                listView.setAdapter(new GitHubRepoAdapter(MainActivity.this, repos));
            }

            @Override
            public void onFailure(Call<List<GitHubRepo>> call, Throwable t) {
                Toast.makeText(MainActivity.this, "Error", Toast.LENGTH_SHORT);
            }
        });
       //**********************************************************
    }
}

The above code may seem a bit complicated but believe me its much complicated than that :P. I will try to explain the above code to you.

The code outside of the ‘*’ boundary is regular android stuff. So lets start with,

Retrofit.Builder builder = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create());

Retrofit retrofit = builder.build();

Retrofit is the base class of the whole Retrofit framework and to configure it, the developers of Retrofit made a another class called Retrofit.Builder class. We use this class to add details about the API like baseUrl and the data converter. Here in above code we have a github base url and as GitHub uses JSON as the data format, we need GSON to convert to and  from the fetched JSON data from the GitHub. For that we use GsonConverterFactory and add it to the retrofit builder.

Now once we have configured the retrofit builder, we build retrofit by using builder.build();

Let me tell you one thing, everything that we did till now was just a preparation to make actual data request. To make actual data request we need a instance of GitHubClient(the interface we made).

GitHubClient client = retrofit.create(GitHubClient.class);
Call<List<GitHubRepo>> call = client.reposForUser("django");

Now the final step is to utilise the Call object that we just created. We can do this in either sync way or in async way but as we know doing it in sync is not a good practice. So lets do it in async way and to achieve that we have a method call enqueue() which expects a Callback as a parameter.

As soon as you start typing new Callback as parameter in method call.enqueue(), android studio do the magic and overrides the two methods as shown below.

Now, either we get data or we don’t get any data because of some error. To handle both the cases, we can write appropriate code in following two methods onResponse and onFailure. If we succeed in fetching data from the web server, we assign the response to the list of repos and setAdapter to the listView as follows.

In case of failure in fetching of data, we display a Toast which simply says “Error”.

call.enqueue(new Callback<List<GitHubRepo>>() {
            @Override
            public void onResponse(Call<List<GitHubRepo>> call, Response<List<GitHubRepo>> response) {
                List<GitHubRepo> repos = response.body();
                listView.setAdapter(new GitHubRepoAdapter(MainActivity.this, repos));
            }

            @Override
            public void onFailure(Call<List<GitHubRepo>> call, Throwable t) {
                Toast.makeText(MainActivity.this, "Error", Toast.LENGTH_SHORT);
            }
        });

If you still have any doubt, comment down your doubt below. I will try my best to resolve your doubt.

-Abhay Maniyar

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s