Retrofit is a type-safe HTTP client for Android. It essentially turns your HTTP API into a Java interface. In layman’s terms, it makes loading APIs into POJOs ridiculously simple. You simply need to create an interface and in it, annotate your API-calling functions and Retrofit automatically transforms it into the API call it needs to be.
Retrofit also offers URL Manipulation, Query Parameters, Request Bodies, and Multipart requests. It also works amazingly well with RxJava as API results can come in the form of Observable streams.
You can read about Retrofit in details here
For this tutorial, I will be using the JSON Placeholder API.
Dependencies
Add these dependencies to your app/build.gradle file. You can see the latest version here.
def retrofit_version = '2.6.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" def kotlin_version = "1.3.2" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_version"
Add <uses-permission android:name="android.permission.INTERNET"/>
to AndroidManifest.xml.
Defining the Model
We want to set up our model as a POJO (Plain Old Java Object). What this essentially means is a class with nothing but their variables and their getter/setter methods. In Kotlin, getter/setters are automatically defined so we don’t need to write them ourselves.
data class Post ( var userId: Int = 0, var id: Int = 0, var title: String = "", @SerializedName("body") var text: String = "" )
You want to match the variable names to the API fields. If you want to put a more fitting name for the variable in your app than the name in the API, annotate it with SerializedName("apifield")
to match the variable to the API field.
Write the Interface
Create a new interface where you will place all your Retrofit calls.
interface JsonPlaceHolderApi { @GET("posts") suspend fun getPosts(): List<Post> }
Each call is a function annotated with @GET("urlextension")
or @POST("urlextension")
, depending on the action you’re performing.
Build the Retrofit
A Retrofit is the object that makes all your Retrofit calls. In your main code, create a retrofit object using the builder, defining the Base URL of your APIs and the Converter Factory as the GsonConverterFactory
.
val serviceApi = Retrofit.Builder() .baseUrl("https://jsonplaceholder.typicode.com/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(JsonPlaceHolderApi::class.java)
Make the Call
Testing the Retrofit suspend method is no different from other functions. Let’s see an example of it.
class PostViewModel(application: Application): AndroidViewModel(application) { private val job = SupervisorJob() private val coroutineContext = Dispatchers.IO + job private val serviceApi: JsonPlaceHolderApi init { serviceApi = Retrofit.Builder() .baseUrl("https://jsonplaceholder.typicode.com/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(JsonPlaceHolderApi::class.java) } fun getPosts() = viewModelScope.launch(coroutineContext) { val posts = serviceApi.getPosts() Log.d("TAG", "POSTS: $posts"); } }
Use PostViewModel
in Activity like following example
class FriendsActivity: AppCompatActivity() { private lateinit var vm: PostViewModel private val TAG = "TAG" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_room) vm = ViewModelProviders.of(this).get(PostViewModel::class.java) vm.getPosts() } }
Or without ViewModel
CoroutineScope(Dispatchers.IO).launch { val response = serviceApi.getPosts() withContext(Dispatchers.Main) { try { if (response.isSuccessful) { //Do something with response e.g show to the UI. } else { toast("Error: ${response.code()}") } } catch (e: HttpException) { toast("Exception ${e.message}") } catch (e: Throwable) { toast("Ooops: Something else went wrong") } } }
To use response.isSuccessful
you should change interface
interface JsonPlaceHolderApi { @GET("posts") suspend fun getPosts(): Response<List<Post>> }