Retrofit Android Get JSON From REST API Tutorial

Hi folks! Today I will share about Retrofit Android, how to get JSON data from REST API. Retrofit is one of REST API clients for Android development. This library helps to make development tasks easier to do some important things like to get and send data on the network. So It must be a waste if you don’t learn this because I personally think that this library is crucial for Android developers.

What will the app look like?

The app will look like this after you finish this tutorial:

Retrofit Android Get JSON From REST API Tutorial

What will you learn?

  • Understand how to implement the Retrofit library on Android development.
  • Understand how to get or read data from REST API on JSON format.
  • Using Android RecyclerView widget to display data from REST API.
  • Displaying images from URL using the Glide library.

Note: In this post, I used Android Studio 3.5.3, make sure you use the latest Android Studio, or if you already install it, be sure to check the latest update. The Kotlin version that I used is Kotlin 1.3.61.

Getting Started – Retrofit Android Get JSON From REST API 

Open your Android Studio and choose to Start a new Android Studio Project. Then set the Application Name RetrofitMarvelHeroes and select Kotlin as the language. Give the Activity Name MainActivity and wait until the Android Studio finishes preparing your project.

Open app/build.gradle file and add the following codes below.

Add this code on top of the file, on the “apply plugin” section:

apply plugin: 'kotlin-kapt'

Next, put this compileOptions code inside the android block:

android {
   …

   compileOptions {
       sourceCompatibility JavaVersion.VERSION_1_8
       targetCompatibility JavaVersion.VERSION_1_8
   }

   ...
}

And the last is add these dependencies inside dependencies block:

dependencies {
   ...

   implementation 'com.google.android.material:material:1.1.0'

   // retrofit for networking
   implementation 'com.squareup.retrofit2:retrofit:2.7.1'
   implementation 'com.squareup.retrofit2:converter-gson:2.7.1'
   implementation 'com.squareup.okhttp3:logging-interceptor:4.4.0'

   // glide to display image
   implementation 'com.github.bumptech.glide:glide:4.11.0'
   kapt 'com.github.bumptech.glide:compiler:4.11.0'

   ...
}

The Android Material library allows you to use the RecyclerView to display the list of data that you will need later on this guide. Next, click Sync Now to begin downloading the required dependencies.

Since you will read data from the Internet, you’re gonna need to use Internet permission on Android. Open the AndroidManifest.xml file and add this <uses-permission> code inside <manifest> tag.

<uses-permission android:name="android.permission.INTERNET" />

Preparing the REST API Endpoint

I already prepare a REST API endpoint for this tutorial here, which is a GET type API.

https://thesimplycoder.herokuapp.com/marvel-heroes

If you open it on your browser, it will display a set of JSON data containing a list of Marvel Superheroes.

{
  "code": 200,
  "data": [
    {
      "_id": "5e4c22e41c9d4400004fd91b",
      "superhero_name": "Iron-Man",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/iron-man.jpg",
      "name": "Tony Stark"
    },
    {
      "_id": "5e4c233e1c9d4400004fd91c",
      "superhero_name": "Captain America",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/captain-america.jpg",
      "name": "Steve Roger"
    },
    {
      "_id": "5e4c23a61c9d4400004fd91d",
      "name": "Bruce Banner",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/hulk.jpg",
      "superhero_name": "Hulk"
    },
    {
      "_id": "5e4c23c61c9d4400004fd91e",
      "superhero_name": "Black Widow",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/black-widow.jpg",
      "name": "Natasha Romanoff"
    },
    {
      "_id": "5e4c23df1c9d4400004fd91f",
      "superhero_name": "Hawkeye",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/hawkeye.jpg",
      "name": "Clint Barton"
    },
    {
      "_id": "5e4c23fd1c9d4400004fd920",
      "superhero_name": "Thor",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/thor.jpg",
      "name": "Thor Odinson"
    },
    {
      "_id": "5e4c241a1c9d4400004fd921",
      "name": "Peter Parker",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/spider-man.jpg",
      "superhero_name": "Spider-Man"
    },
    {
      "_id": "5e4c24451c9d4400004fd922",
      "superhero_name": "Doctor Strange",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/doctor-strange.jpg",
      "name": "Stephen Strange"
    },
    {
      "_id": "5e4c24631c9d4400004fd923",
      "superhero_name": "Wolverine",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/wolverine.jpg",
      "name": "Logan"
    },
    {
      "_id": "5e4c24731c9d4400004fd924",
      "name": "Peter Quill",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/star-lord.jpg",
      "superhero_name": "Star-Lord"
    },
    {
      "_id": "5e4c25001c9d4400004fd925",
      "superhero_name": "Black Panther",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/black-panther.jpg",
      "name": "T'challa"
    },
    {
      "_id": "5e4c25331c9d4400004fd926",
      "name": "Scott Lang",
      "photo": "https://thesimplycoder.com/wp-content/uploads/2020/02/ant-man.jpg",
      "superhero_name": "Ant-Man"
    }
  ]
}

Well, what we’re going to do is to read that data and display them on our Android app. The Retrofit will just take care of that! It will automatically convert that data to become a POJO type model on our app so you can access and read it easily. So let’s proceed to the next step.

Preparing the Data Model

Since my JSON data contain a wrapper for the data object, we need to create a wrapper class named ResponseData.kt.

package com.thesimplycoder.retrofitmarvelheroes

data class ResponseData<T> (
   val code: Int,
   val data: T
)

Next, create another new Kotlin class file named Superhero.kt.

package com.thesimplycoder.retrofitmarvelheroes

import com.google.gson.annotations.SerializedName

class Superhero {

   @SerializedName("superhero_name")
   var superheroName: String = ""

   var name: String = ""
   var photo: String = ""
}

Setting up the Retrofit

Create an interface class named ApiService.kt for listing the REST endpoint.

package com.thesimplycoder.retrofitmarvelheroes

import retrofit2.Call
import retrofit2.http.GET

interface ApiService {

   @GET("marvel-heroes")
   fun listHeroes(): Call<ResponseData<List<Superhero>>>

}

The function listHeroes() will call the endpoint of “marvel-heroes” and will automatically convert the JSON response to a ResponseData<List<Superhero>> object. How convenient! For more info on Retrofit action types like POST, PUT, PATCH, etc, you can go here.

Next, add a new class ApiManager.kt file.

package com.thesimplycoder.retrofitmarvelheroes

import android.util.Log
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

class ApiManager {

   private var apiService: ApiService? = null

   init {
       createService()
   }

   val service: ApiService get() = apiService!!

   private fun createService() {
       val loggingInterceptor =
           HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
               override fun log(message: String) {
                   Log.i("Retrofit", message)
               }
           })

       loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY

       val client = OkHttpClient.Builder()
           .readTimeout(30, TimeUnit.SECONDS)
           .connectTimeout(30, TimeUnit.SECONDS)
           .writeTimeout(30, TimeUnit.SECONDS)
           .addInterceptor(loggingInterceptor)
           .build()

       val retrofit: Retrofit = Retrofit.Builder()
           .client(client)
           .baseUrl("https://secret-cliffs-40396.herokuapp.com/")
           .addConverterFactory(GsonConverterFactory.create())
           .build()

       apiService = retrofit.create<ApiService>(ApiService::class.java)
   }

   companion object {

       private var instance: ApiManager? = null

       fun getInstance(): ApiManager {
           return instance ?: synchronized(this) {
               ApiManager().also { instance = it }
           }
       }
   }

}

This class is for setting up the Retrofit client. Retrofit Android uses OkHttpClient as its networking client and GsonConverterFactory to automatically convert the data model. On that code, I also put HttpLoggingInterceptor to automatically logs all the API response to Android Studio Logcat for testing/debugging purposes.

Setting up RecyclerView and Data Adapter

Create a new layout file inside res/layout named item_superhero.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="wrap_content">

   <LinearLayout
       android:id="@+id/container"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="horizontal"
       android:background="?selectableItemBackground"
       android:clickable="true"
       android:paddingLeft="20dp"
       android:paddingRight="20dp"
       android:paddingTop="12dp"
       android:paddingBottom="12dp"
       android:gravity="center_vertical">

       <ImageView
           android:id="@+id/ivPhoto"
           android:layout_width="50dp"
           android:layout_height="50dp"
           />

       <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:orientation="vertical"
           android:layout_marginLeft="12dp">

           <TextView
               android:id="@+id/tvSuperheroName"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:textStyle="bold"
               android:textSize="16sp"
               android:text="Superhero Name"
               />

           <TextView
               android:id="@+id/tvName"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_marginTop="2dp"
               android:text="Name"
               />

       </LinearLayout>

   </LinearLayout>

   <View
       android:layout_width="match_parent"
       android:layout_height="1dp"
       android:background="#dedede"
       />

</LinearLayout>

After that, add a new class SuperheroAdapter.kt file.

package com.thesimplycoder.retrofitmarvelheroes

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import kotlinx.android.synthetic.main.item_superhero.view.*

class SuperheroAdapter : RecyclerView.Adapter<SuperheroAdapter.ViewHolder>() {

   private lateinit var itemList: List<Superhero>
   lateinit var context: Context

   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
       context = parent.context
       val view = LayoutInflater.from(context).inflate(R.layout.item_superhero, parent, false)
       return ViewHolder(view)
   }

   override fun getItemCount(): Int {
       return if (::itemList.isInitialized) itemList.size else 0
   }

   override fun onBindViewHolder(holder: ViewHolder, position: Int) {
       holder.bind()
   }

   fun updateData(list: List<Superhero>) {
       itemList = list;
       notifyDataSetChanged()
   }

   inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

       fun bind() {
           val item = itemList.get(adapterPosition)

           itemView.tvName.text = item.name
           itemView.tvSuperheroName.text = item.superheroName

           Glide.with(context)
               .load(item.photo)
               .diskCacheStrategy(DiskCacheStrategy.ALL)
               .circleCrop()
               .into(itemView.ivPhoto)
       }
   }
}

It is just a typical Adapter code for Android RecyclerView. If you want to learn more about working with Android RecyclerView, you can go here.

Open the activity_main.xml file inside the res/layout directory and replace the layout code:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

   <androidx.recyclerview.widget.RecyclerView
       android:id="@+id/rvData"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
       />

   <ProgressBar
       android:id="@+id/pbLoading"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerInParent="true"
       />

</RelativeLayout>

After that, open the MainActivity.kt file and replace the code like this:

package com.thesimplycoder.retrofitmarvelheroes

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MainActivity : AppCompatActivity() {

   val TAG = MainActivity::class.java.name

   val itemList = ArrayList<Superhero>()
   lateinit var adapter: SuperheroAdapter

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)

       // initialize adapter
       adapter = SuperheroAdapter()
       rvData.adapter = adapter

       // call api to get the data from network
       loadData()
   }

   private fun loadData() {
       // show loading progress bar
       pbLoading.visibility = View.VISIBLE

       ApiManager.getInstance().service.listHeroes()
           .enqueue(object : Callback<ResponseData<List<Superhero>>> {

               override fun onResponse(
                   call: Call<ResponseData<List<Superhero>>>,
                   response: Response<ResponseData<List<Superhero>>>
               ) {
                   val listData: List<Superhero> = response.body()!!.data

                   // updating data from network to adapter
                   itemList.clear()
                   itemList.addAll(listData)
                   adapter.updateData(itemList)

                   // hide loading progress bar
                   pbLoading.visibility = View.GONE
               }

               override fun onFailure(call: Call<ResponseData<List<Superhero>>>, t: Throwable) {
                   // if there is error while get data from network

                   Log.e(TAG, "Error on loading data")
                   pbLoading.visibility = View.GONE
               }

           })
   }

}

The loadData() function is to load data or call the marvel-heroes endpoint using the Retrofit client. When getting the data is successful, it will execute the onResponse() callback so that you could update your data list here. On the other hand, the onFailure() callback only invoked when there is an error while getting data.

Try run your app and see what happens!

Where to go next?

You can download this full code from the link below:

Download final code

Be sure to check my other cool posts here about:

I hope you like my post, comment and share it with love!

You may also like...

Join the discussion...

This site uses Akismet to reduce spam. Learn how your comment data is processed.