Nearly every modern Android app needs to communicate with a server over the internet. Building a networking layer from scratch is complex and error-prone. Thankfully, the Android community has established a clear winner for this task: the powerful combination of Retrofit and OkHttp.
Many developers use them together without fully understanding their relationship. Retrofit isn't a replacement for OkHttp; it's a brilliant abstraction layer built on top of it. Understanding how they work together will allow you to build a clean, efficient, and highly customizable networking layer.
The Relationship: Brains and Brawn
Think of their relationship like this:
- OkHttp is the engine. It's a powerful and efficient HTTP client that handles all the low-level work: opening connections, managing caches, handling retries and redirects, and processing raw request and response data.
- Retrofit is the clean, type-safe API on top. It's the "brains" of the operation. You define your API endpoints in a simple Kotlin interface, and Retrofit generates all the code to make those calls using OkHttp. It handles things like URL building, request body serialization, and response parsing.
The Basic Setup: Making Your First Call
Let's see how easy it is to fetch a list of users from a REST API.
Step 1: Add Dependencies
You'll need Retrofit, OkHttp, and a converter library (like Gson or Moshi) to handle JSON parsing.
// In app/build.gradle.kts
implementation("com.squareup.retrofit2:retrofit:2.11.0") // Use latest
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") // For logging
Step 2: Define the API Interface
This is where Retrofit's magic shines. You create a simple Kotlin interface and use annotations to describe your API endpoints.
interface ApiService {
@GET("users")
suspend fun getUsers(): List<User>
@GET("users/{id}")
suspend fun getUserById(@Path("id") userId: String): User
}
Step 3: Build the Retrofit Instance
You create a single Retrofit instance for your app, telling it the base URL of your API and which converter to use. It's common to use a dependency injection library like Hilt to provide this as a singleton.
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
// Now you can make the call in a coroutine
viewModelScope.launch {
val users = apiService.getUsers()
// ... do something with the list of users
}
That's it! Retrofit handles creating the full URL, making the network call with OkHttp, parsing the JSON response into a List<User>
, and returning it, all from that simple interface definition.
The Superpower: OkHttp Interceptors
What if you need to modify every single request before it's sent? For example, adding an authentication header. This is where you drop down to the OkHttp level and use an Interceptor.
An interceptor is a powerful class that can observe, modify, and even short-circuit requests and responses. Let's create one to add an `Authorization` header.
Creating an Auth Interceptorclass AuthInterceptor(private val authToken: String) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
// Get the original request
val originalRequest = chain.request()
// Build a new request, adding the Authorization header
val newRequest = originalRequest.newBuilder()
.header("Authorization", "Bearer $authToken")
.build()
// Proceed with the new, modified request
return chain.proceed(newRequest)
}
}
Now, you just need to create an OkHttp client with this interceptor and tell Retrofit to use it.
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(AuthInterceptor("YOUR_SECRET_TOKEN"))
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) // Also add a logger
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient) // Tell Retrofit to use our custom client
.addConverterFactory(GsonConverterFactory.create())
.build()
Now, every single API call made through this Retrofit instance will automatically have the `Authorization` header attached. You can use interceptors for logging, caching, handling retries, and so much more.
By understanding that Retrofit is the user-friendly API and OkHttp is the powerful engine underneath, you can build a networking layer that is not only clean and type-safe but also incredibly flexible and robust.