Android Khoa Khoa học máy tính - VKU
Retrofit Library
1.19. Android Retrofit Library
Android Retrofit Library is type safe HTTP client for android and java, developed
by Square Inc., and uses OkHttp library for HTTP requests. This library makes
developers life easy to handle JSON requests via REST based web service. You can
make GET, POST, PUT, DELETE or PATCH requests using this library. Generally,
1
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
GSon is used as converter for data serialization. However, you can add custom
converters too for XML or other protocols.
With the help of this library, downloading JSON or XML data from a web API becomes
easy. In a Retrofit library, once the data is downloaded, it is parsed into a Plain Old Java
Object (POJO) which must be defined for each “resource” in the response. Retrofit is an
easy and fast library to retrieve and upload data via a REST-based web service.
Retrofit manages the process of receiving, sending, and creating HTTP requests and
responses. It resolves issues before sending an error and crashing the application.
1.19.1. Features Of Retrofit
+ Retrofit is very fast.
+ Retrofit enables direct communication with the web service.
+ Retrofit supports dynamic URLs.
+ Retrofit is easy to use and understand.
+ Retrofit supports both synchronous and asynchronous network requests.
+ Retrofit supports converters.
+ Retrofit supports request cancellation.
+ Retrofit supports post requests and multipart uploads.
1.19.2. Advantages of Android Retrofit
+ Retrofit Android is very simple to use. It essentially lets you treat API calls as simple
Java or Kotlin method calls, so you only define which URLs to hit and the types of the
request/response parameters as Java or Kotlin classes.
+ The entire network call JSON/XML parsing is completely handled by it (with help from
Gson for JSON parsing), along with support for arbitrary formats with pluggable
serialization/deserialization.
1.19.3. Disadvantages Of Retrofit
2
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
+ Retrofit does not support image loading.
+ Retrofit requires other libraries such as Glide and Picasso.
1.19.4. Classes Used In Retrofit
+ Model Class: A model class contains the objects to be obtained from the JSON file. This
class represents JSON data in kotlin.
ex1:
import com.google.gson.annotations.SerializedName
data class Lop (
@SerializedName("malop")
var malop: Int? = null,
@SerializedName("tenlop")
var tenlop: String? = null
)
=> Note: The @SerializedName annotation can be used to serialize a field with a
different name instead of an actual field name. We can provide the expected serialized
name as an annotation attribute. Gson can make sure to read or write a field with the
provided name.
ex2:
data class Student(
val id: Int,
val name: String,
val email: String,
val phone: String
)
+ Retrofit Instance (Builder class): This is a Java or Kotlin class. It is used to send
requests to an API. The class that builds and configure an instance of retrofit. This instance
will be used to send HTTP requests.
ex1:
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RestClient {
private val BASE_URL = "http://192.168.4.2:8080"
private var mRetrofit: Retrofit? = null
val client: Retrofit
get() {
if (mRetrofit == null) {
3
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
mRetrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return this.mRetrofit!!
}
}
=> Note that we are creating only one instance of Retrofit. Whenever get method is
called, it checks if there is already an instance of retrofit or not. If not, a new instance is
created. Otherwise, old instance is returned. BASE_URL represents base url of all the
requests.
ex2:
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import java.util.concurrent.TimeUnit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient {
private const val BASE_URL = "http://192.168.56.1:81/studentws/"
private val gson = GsonBuilder().create()
private val okHttpClient = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
fun create(): StudentApi {
return retrofit.create(StudentApi::class.java)
}
}
+ Retrofit Interface (ApiService): This is a Java or Kotlin interface. It is used to define
endpoints. This interface represents possible operations (GET, PUT, PATCH,
DELETE, POST) in apis.
ex1:
import retrofit2.Call
import retrofit2.http.GET
interface ApiService {
4
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
@GET("/qllop/")
fun fetchLops(): Call<LopList>
}
Note:
+ @GET(“Url”): Represents GET request with given Url. Remember we have already
defined base url in RestClient.kt class while building an instance of retrofit.
+ Call<LopList>: This represents an object of LopList that will be returned by the
request.
+ fetchLops(): Call this method to send request to server.
ex2:
import okhttp3.ResponseBody
import retrofit2.http.GET;
interface StudentApi {
//Method retrieves a list of Student objects from the web API
@GET("display.php")
suspend fun getStudents(): ResponseBody
}
1.19.5. Android Retrofit Speed
Compare with Volley and AsyncTask, Retrofit provides a very fast response to request.
1.19.6. Steps to create a retrofit android
5
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
- Step 1: Adding Retrofit Dependency
+ Open the app/build.gradle file in your Android project.
+ Add the necessary dependency inside the dependencies block.
- Add viewBinding true in app/build.gradle file.
android {
// OTHER CODE...
buildFeatures {
viewBinding true
}
}
- Add Retrofit Library in app/build.gradle file.
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// JSON Parsing
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.squareup.retrofit2:converter-gson:2.7.2'
implementation 'com.squareup.okhttp3:okhttp:3.6.0'
- Step 2: Adding Internet Permission
We need to add internet permission in AndroidMinfest.xml.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<application android:usesCleartextTraffic="true" tools:targetApi="31">
…
</application>
</manifest>
- Step 3: Creating a Model Class
+ For data retrieval using Retrofit 2, a model class is required.
+ The model class structure should match the JSON data format.
ex:
Before creating the model, we need to know what type of response we will be receiving.
+ volley_array.json
[
{
6
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
"id":"1",
"image":"http://velmm.com/images/bottom_navigationview/coco.jpg",
"title":"Coco"
},
{
"id":"2",
"image":"http://velmm.com/images/bottom_navigationview/terminator_2.jpg",
"title":"Terminator 2: Judgment Day 3D"
},
{
"id":"3",
"image":"http://velmm.com/images/bottom_navigationview/dunkirk.jpg",
"title":"Dunkirk"
},
{
"id":"4",
"image":"http://velmm.com/images/bottom_navigationview/the_salesman.jpg",
"title":"The Salesman"
},
{
"id":"5",
"image":"http://velmm.com/images/bottom_navigationview/lion.png",
"title":"Lion"
},
{
"id":"6",
"image":"http://velmm.com/images/bottom_navigationview/star_war.jpg",
"title":"Star Wars: The Last Jedi"
},
{
"id":"7",
"image":"http://velmm.com/images/bottom_navigationview/thor_ragnarok.jpg",
"title":"Thor: Ragnarok"
},
{
"id":"8",
"image":"http://velmm.com/images/bottom_navigationview/blade_runner_2049.jpg",
"title":"Blade Runner 2049"
},
{
"id":"9",
"image":"http://velmm.com/images/bottom_navigationview/borg_mcenroe.jpg",
"title":"Borg McEnroe"
7
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
},
{
"id":"10",
"image":"http://velmm.com/images/bottom_navigationview/wonder.jpg",
"title":"Wonder"
}
]
=> In my JSON response, we are having the list of movies with name, year, and director
properties. So, Our Model class will be like a Movie as class name and name, year, and
director are properties.
+ Movie.kt
data class Movie(
@SerializedName("title")
var title: String,
@SerializedName("image")
var imageUrl: String
)
=> @SerializedName is used to map the POJO object into to JSON response properties.
- Step 4. Create The Retrofit Instance
We need to create the Retrofit instance to send the network requests. We need to use
the Retrofit Builder class and specify the base URL for the service.
+ ApiClient.kt
object ApiClient {
var BASE_URL = "YOUR_BASE_URL"
private var retrofit: Retrofit? = null
val client: Retrofit?
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit
}
}
- Step 5. Setting Up The Retrofit Interface
Retrofit provides the list of annotations for each HTTP method:
@GET, @POST, @PUT, @DELETE, @PATCH, or @HEAD.
8
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
The endpoints are defined inside an interface using retrofit annotations to encode
details about the parameters and request method. T return value is always a
parameterized Call<T>.
Because the POJO classes are wrapped into a typed Retrofit Call class.
Method Parameters :
@Body: Sends Java or Kotlin objects as the request body.
@Url : use dynamic URLs.
@Query: We can simply add a method parameter with @Query() and a query parameter
name, describing the type.
=> To URL encode a query using the form: @Query(value = auth_token,encoded =
true) String auth_token
+ ApiInterface.kt
interface ApiInterface {
@get:GET("volley_array.json")
val movies: Call<List<Movie?>?>?
}
- Step 6. Consume The REST Web Service
Now we are ready to consume the REST web service. In Our MainActivity.kt, First,
need to initialize the ApiClient.
var apiService: ApiInterface = ApiClient.getClient().create(ApiInterface::class.java)
=> After the initialization, we call the getMovies() interface and implement the
CallBacks. As part of the implementation, we need to override the onResponse() and
onFailure().
=> If the request succeeds the callback will come into onResponse(). If any error in the
request the callback will go into onFailure(). In onResponse(), we can get our response
from the response body.
var apiService:ApiInterface = ApiClient.getClient().create(ApiInterface.class)
var call:Call<List<Movie>> = apiService.getMovies();
call.enqueue(object : Callback<List<Movie>>{
override fun onResponse(call: Call<List<Movie>>, response:
Response<List<Movie>>){
override fun onFailure(call: Call<List<Movie>>, t: Throwable)
{
Log.d("TAG","Response = " + t.toString());
}
})
- Step 7. Set Retrofit response data into the recyclerview
9
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
+ RecyclerAdapter.kt
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
class RecyclerAdapter(val context: Context) :
RecyclerView.Adapter<RecyclerAdapter.MyViewHolder>() {
var movieList : List<Movie> = listOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
MyViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_adapter,parent,false)
return MyViewHolder(view)
}
override fun getItemCount(): Int {
return movieList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.tvMovieName.text = movieList.get(position).title
Glide.with(context).load(movieList.get(position).image)
.apply(RequestOptions().centerCrop())
.into(holder.image)
}
fun setMovieListItems(movieList: List<Movie>){
this.movieList = movieList;
notifyDataSetChanged()
}
class MyViewHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
10
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
val tvMovieName: TextView = itemView!!.findViewById(R.id.title)
val image: ImageView = itemView!!.findViewById(R.id.image)
}
}
+ ApiInterface.kt
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
interface ApiInterface {
@GET("volley_array.json")
fun getMovies() : Call<List<Movie>>
companion object {
var BASE_URL = "http://velmm.com/apis/"
fun create() : ApiInterface {
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build()
return retrofit.create(ApiInterface::class.java)
}
}
}
+ Movie.kt
data class Movie(var title: String, var image: String)
+ MainActivity.kt
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Call
11
Gv: Võ Ngọc Đạt
Android Khoa Khoa học máy tính - VKU
import retrofit2.Callback
import retrofit2.Response
class MainActivity : AppCompatActivity() {
lateinit var recyclerView: RecyclerView
lateinit var recyclerAdapter: RecyclerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView = findViewById(R.id.recyclerview)
recyclerAdapter = RecyclerAdapter(this)
recyclerview.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = recyclerAdapter
val apiInterface = ApiInterface.create().getMovies()
//apiInterface.enqueue( Callback<List<Movie>>())
apiInterface.enqueue( object : Callback<List<Movie>>{
override fun onResponse(call: Call<List<Movie>>?, response:
Response<List<Movie>>?) {
if(response?.body() != null)
recyclerAdapter.setMovieListItems(response.body()!!)
}
override fun onFailure(call: Call<List<Movie>>?, t: Throwable?) {
}
})
}
}
(Lab 01, 02, 03, 04. Building an Kotlin Android Application. We will learn about using
Retrofit Library for reading a value from web service)
(https://square.github.io/retrofit/)
12
Gv: Võ Ngọc Đạt