Bird
Raised Fist0
Android Kotlinmobile~20 mins

OkHttp interceptors in Android Kotlin - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Interceptor Demo Screen
This screen demonstrates how to use OkHttp interceptors to log HTTP request and response details.
Target UI
-------------------------
| Interceptor Demo       |
|-----------------------|
| [Make Request Button] |
|                       |
| Response:             |
| <empty>               |
-------------------------
Add a button labeled 'Make Request' that triggers an HTTP GET request to https://jsonplaceholder.typicode.com/todos/1
Use OkHttp client with an interceptor that logs the request URL and response code
Display the response body text below the button after the request completes
Handle errors gracefully and show an error message if the request fails
Starter Code
Android Kotlin
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.Interceptor
import okhttp3.logging.HttpLoggingInterceptor
import java.io.IOException
import kotlin.concurrent.thread

class InterceptorDemoActivity : AppCompatActivity() {
    private lateinit var responseTextView: TextView

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

        val makeRequestButton = findViewById<Button>(R.id.makeRequestButton)
        responseTextView = findViewById(R.id.responseTextView)

        makeRequestButton.setOnClickListener {
            // TODO: Implement HTTP request with OkHttp and interceptor
        }
    }
}
Task 1
Task 2
Task 3
Solution
Android Kotlin
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException
import kotlin.concurrent.thread

class InterceptorDemoActivity : AppCompatActivity() {
    private lateinit var responseTextView: TextView

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

        val makeRequestButton = findViewById<Button>(R.id.makeRequestButton)
        responseTextView = findViewById(R.id.responseTextView)

        // Create OkHttpClient with interceptor
        val client = OkHttpClient.Builder()
            .addInterceptor(object : Interceptor {
                override fun intercept(chain: Interceptor.Chain): Response {
                    val request = chain.request()
                    // Log request URL
                    println("Request URL: ${request.url}")
                    val response = chain.proceed(request)
                    // Log response code
                    println("Response code: ${response.code}")
                    return response
                }
            })
            .build()

        makeRequestButton.setOnClickListener {
            thread {
                try {
                    val request = Request.Builder()
                        .url("https://jsonplaceholder.typicode.com/todos/1")
                        .build()
                    val response = client.newCall(request).execute()
                    val body = response.body?.string() ?: "No response body"
                    runOnUiThread {
                        responseTextView.text = body
                    }
                } catch (e: IOException) {
                    runOnUiThread {
                        responseTextView.text = "Request failed: ${e.message}"
                    }
                }
            }
        }
    }
}

We create an OkHttpClient and add an interceptor that prints the request URL and response code to the console. When the user taps the 'Make Request' button, we run a network call on a background thread to avoid blocking the UI. The GET request fetches JSON data from the example API. After getting the response, we update the TextView on the main thread to show the response body. If the request fails, we show an error message instead.

Final Result
Completed Screen
-------------------------
| Interceptor Demo       |
|-----------------------|
| [Make Request Button] |
|                       |
| Response:             |
| {                     |
|   "userId": 1,       |
|   "id": 1,           |
|   "title": "...",   |
|   "completed": false |
| }                     |
-------------------------
User taps 'Make Request' button
App logs request URL and response code in console
Response JSON text appears below the button
If network fails, error message appears instead
Stretch Goal
Add a second interceptor that adds a custom header 'X-App-Name: InterceptorDemo' to every request
💡 Hint
Use OkHttpClient.Builder().addInterceptor() again to add another interceptor that modifies the request headers before proceeding

Practice

(1/5)
1. What is the main purpose of an OkHttp interceptor in Android Kotlin?
easy
A. To manage database transactions
B. To observe and modify network requests and responses
C. To create UI components dynamically
D. To handle user input events

Solution

  1. Step 1: Understand the role of interceptors

    OkHttp interceptors allow you to watch and change network requests and responses before they are sent or after they are received.
  2. Step 2: Compare with other options

    The other options relate to managing database transactions, creating UI components dynamically, and handling user input events, which are unrelated to network interception.
  3. Final Answer:

    To observe and modify network requests and responses -> Option B
  4. Quick Check:

    Interceptor purpose = Observe and modify network calls [OK]
Hint: Interceptors always deal with network requests/responses [OK]
Common Mistakes:
  • Confusing interceptors with UI or database components
  • Thinking interceptors handle user input
  • Assuming interceptors manage app navigation
2. Which of the following is the correct way to implement an OkHttp interceptor in Kotlin?
easy
A. fun intercept(chain: Chain): Response { return chain.proceed(chain.request()) }
B. class MyInterceptor : Runnable { override fun run() { // code } }
C. class MyInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { return chain.proceed(chain.request()) } }
D. class MyInterceptor { fun intercept(chain: Interceptor.Chain) { // code } }

Solution

  1. Step 1: Check the interface implementation

    OkHttp interceptors implement the Interceptor interface and override the intercept() method with the correct signature.
  2. Step 2: Validate method signature and return type

    The intercept method must take Interceptor.Chain and return a Response object, as shown in class MyInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { return chain.proceed(chain.request()) } }.
  3. Final Answer:

    Correct interceptor implementation with override and proper method signature -> Option C
  4. Quick Check:

    Interceptor class implements Interceptor interface [OK]
Hint: Interceptor must override intercept(chain: Interceptor.Chain): Response [OK]
Common Mistakes:
  • Not implementing Interceptor interface
  • Wrong method signature or missing return type
  • Using unrelated interfaces like Runnable
3. Given this interceptor code snippet, what will be the value of the "User-Agent" header in the outgoing request?
class UserAgentInterceptor : Interceptor {
  override fun intercept(chain: Interceptor.Chain): Response {
    val newRequest = chain.request().newBuilder()
      .header("User-Agent", "MyAppAgent")
      .build()
    return chain.proceed(newRequest)
  }
}
medium
A. The request will have "User-Agent" header set to "MyAppAgent"
B. The request will have no "User-Agent" header
C. The request will have "User-Agent" header set to the default OkHttp value
D. The code will cause a compile error

Solution

  1. Step 1: Analyze header modification

    The interceptor creates a new request builder from the original request and sets the "User-Agent" header explicitly to "MyAppAgent".
  2. Step 2: Understand header effect

    Setting the header with .header() replaces any existing "User-Agent" header with the new value.
  3. Final Answer:

    "User-Agent" header is set to "MyAppAgent" in the outgoing request -> Option A
  4. Quick Check:

    Header set by interceptor = "MyAppAgent" [OK]
Hint: .header() replaces existing header values [OK]
Common Mistakes:
  • Assuming header is appended instead of replaced
  • Thinking default headers remain unchanged
  • Confusing compile errors with runtime behavior
4. Identify the error in this interceptor code snippet:
class LoggingInterceptor : Interceptor {
  override fun intercept(chain: Interceptor.Chain): Response {
    val request = chain.request()
    println("Request URL: ${request.url}")
    val response = chain.proceed(request)
    println("Response code: ${response.code}")
  }
medium
A. Missing return statement for the Response object
B. Incorrect method name; should be interceptRequest
C. Cannot use println inside intercept method
D. Request object is not created properly

Solution

  1. Step 1: Check method return type

    The intercept method must return a Response object, but this code does not return anything.
  2. Step 2: Verify other code parts

    Method name and usage of println are valid; request creation is correct.
  3. Final Answer:

    Missing return statement for the Response object -> Option A
  4. Quick Check:

    intercept() must return Response [OK]
Hint: Always return the Response from intercept() [OK]
Common Mistakes:
  • Forgetting to return the response
  • Renaming intercept method incorrectly
  • Thinking println is disallowed in intercept
5. You want to create an OkHttp interceptor that retries a request up to 3 times if the response code is 500 (server error). Which approach correctly implements this behavior?
hard
A. Use a separate thread to retry the request after intercept() returns
B. Throw an exception inside intercept() when response code is 500 to trigger retry
C. Modify the request headers to include "Retry: 3" and proceed once
D. Override intercept() to loop up to 3 times calling chain.proceed(request) until response.code != 500 or max retries reached

Solution

  1. Step 1: Understand retry logic in intercept()

    Retries must happen inside intercept() by calling chain.proceed(request) multiple times if needed.
  2. Step 2: Evaluate options for retry implementation

    Override intercept() to loop up to 3 times calling chain.proceed(request) until response.code != 500 or max retries reached correctly loops and retries up to 3 times checking response code. The other options do not implement retry correctly or rely on unsupported mechanisms.
  3. Final Answer:

    Loop inside intercept() to retry request up to 3 times on 500 response -> Option D
  4. Quick Check:

    Retry logic = loop in intercept() calling chain.proceed() [OK]
Hint: Retries must be done inside intercept() by repeating chain.proceed() [OK]
Common Mistakes:
  • Trying to retry outside intercept() method
  • Assuming headers control retry automatically
  • Throwing exceptions to trigger retry without handling
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard