Most mobile applications nowadays fetch data from remote APIs. When building a similar application in Android, you might wonder what library to use for this purpose. One popular option you might want to consider is Retrofit.
In this Note, I'll show the most basic example of using Retrofit in a newly created Android (Kotlin) project.
We will be making a simple app that displays a list of todos taken from this API. Follow the instructions below to start.
- Create a new Android project with Empty Activity. Make sure to set the language to Kotlin and enable Use androidx.* artifacts option.
- Import Retrofit and its complementary libraries (Gson and Gson converter) to the project by modifying the module-level
build.gradlelike this:
dependencies { ... other dependencies implementation 'com.squareup.retrofit2:retrofit:2.6.0' implementation 'com.squareup.retrofit2:converter-gson:2.6.0' implementation 'com.google.code.gson:gson:2.8.5' }When writing this, the latest Retrofit version is 2.6.0. Make sure to check the latest version here and always use the latest version. The same applies to the rest of the libraries.
- Add permission to use the Internet in
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hanmajid.kotlintutorialboilerplate"> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest> - Create an XML layout for todo item named
todo_item.xmllike this:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" tools:text="Title" android:id="@+id/title" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent" android:layout_marginLeft="16dp" android:layout_marginStart="16dp" android:textSize="24sp"/> <TextView tools:text="Completed" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/completed" android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="@+id/title" app:layout_constraintStart_toStartOf="@+id/title" /> <View android:id="@+id/divider" android:layout_width="match_parent" android:layout_height="1dp" android:background="?android:attr/listDivider" tools:layout_editor_absoluteX="-16dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@+id/completed" android:layout_marginTop="16dp" /> </androidx.constraintlayout.widget.ConstraintLayout>The layout will look like this:

- Change the content of
activity_main.xmlto be like this:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView tools:listitem="@layout/todo_item" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/recycler_view"/> </androidx.constraintlayout.widget.ConstraintLayout>Here's what
activity_main.xmllooks like now:
- For simplicity's sake, the rest of the code will be declared inside
MainActivity.kt. In a real application, you might want to separate every new class (Todo,TodoAdapter,TodoService) into a new file.
Here's the content of theMainActivity.kt:
package com.hanmajid.kotlintutorialboilerplate import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import retrofit2.Call import retrofit2.Callback import retrofit2.Response import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import retrofit2.http.GET class MainActivity : AppCompatActivity() { private lateinit var recyclerView: RecyclerView private var data: ArrayList<Todo> = ArrayList() private lateinit var adapter: RecyclerView.Adapter<*> private lateinit var manager: RecyclerView.LayoutManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) var retrofit: Retrofit = Retrofit.Builder() .baseUrl("https://jsonplaceholder.typicode.com") .addConverterFactory(GsonConverterFactory.create()) .build() manager = LinearLayoutManager(this) adapter = TodoAdapter(data) recyclerView = findViewById(R.id.recycler_view) recyclerView.layoutManager = manager recyclerView.adapter = adapter val todoService: TodoService = retrofit.create(TodoService::class.java) val list = todoService.listTodos() list.enqueue(object: Callback<List<Todo>> { override fun onFailure(call: Call<List<Todo>>, t: Throwable) { } override fun onResponse(call: Call<List<Todo>>, response: Response<List<Todo>>) { if(response.code() === 200) { data.addAll(response.body()!!) recyclerView.adapter!!.notifyDataSetChanged() } } }) } } class TodoAdapter(private var data: List<Todo>): RecyclerView.Adapter<TodoAdapter.ViewHolder>() { class ViewHolder(view: View): RecyclerView.ViewHolder(view) { var title: TextView = view.findViewById(R.id.title) var completed: TextView = view.findViewById(R.id.completed) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder( LayoutInflater.from(parent.context).inflate(R.layout.todo_item, parent, false) ) } override fun getItemCount() = data.size override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.title.text = data[position].title holder.completed.text = if(data[position].completed) "Completed" else "Not Completed" } } interface TodoService { @GET("todos") fun listTodos(): Call<List<Todo>> } class Todo ( val id: Integer, val userId: Integer, val title: String, val completed: Boolean ) - That's it! Now run your application and see the result for yourself. It should look like this:

That's it for now!