OkHttp (Java)
The previous lesson used HttpURLConnection to talk to a server and showed why network calls must run off the main thread. OkHttp is the HTTP client that most real Android apps reach for instead: it is efficient (connection pooling, transparent GZIP, response caching), has a clean request/response API, and is the foundation that libraries like Retrofit are built on top of.
In this lesson we will use OkHttp directly in our RecipeBox app: fetching the list of recipes from a server and submitting a newly created recipe.
Adding the Dependency
OkHttp is added through Gradle like any other library. In your module's build.gradle:
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
}
Building a GET Request
An OkHttpClient is the reusable object that actually executes requests. Create one instance and share it across your app instead of creating a new client per call.
// RecipeApi.java
public class RecipeApi {
private final OkHttpClient client = new OkHttpClient();
public void fetchRecipes(Callback callback) {
Request request = new Request.Builder()
.url("https://api.recipebox.example.com/recipes")
.get()
.build();
client.newCall(request).enqueue(callback);
}
}
- Request.Builder() assembles the URL, HTTP method, headers, and body.
- .get() is the default method, shown here for clarity.
- client.newCall(request) creates a Call object representing this one execution.
Executing Asynchronously with enqueue()
OkHttp calls can run .execute() synchronously (blocking – never on the main thread) or .enqueue() asynchronously. For UI code, always use enqueue(): OkHttp automatically runs the request on a background thread pool for you, and delivers onResponse() / onFailure() back on that same background thread – not the main thread.
// Inside RecipeListActivity.java
api.fetchRecipes(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(() -> showError("Could not load recipes"));
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
runOnUiThread(() -> showError("Server error: " + response.code()));
return;
}
String json = response.body().string();
List<Recipe> recipes = parseRecipes(json);
runOnUiThread(() -> adapter.setRecipes(recipes));
}
});
- Just like android-http-basics.php explained for HttpURLConnection, touching views from a background thread crashes the app – so every UI update here is wrapped in runOnUiThread().
- response.body().string() reads the entire body into a String. It can only be read once.
- response.isSuccessful() checks for a 2xx status code before trusting the body.
POST Request with a JSON Body
Submitting a new recipe means sending a JSON body along with the request:
// RecipeApi.java
private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
public void createRecipe(Recipe recipe, Callback callback) {
String json = new Gson().toJson(recipe);
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url("https://api.recipebox.example.com/recipes")
.post(body)
.build();
client.newCall(request).enqueue(callback);
}
- MediaType tells the server what format the body is in.
- RequestBody.create(json, JSON) wraps the JSON string for the request.
- The Callback passed to .post(body) works exactly the same as the GET example – still asynchronous, still requires runOnUiThread() for UI updates.
Logging Requests with an Interceptor
While developing, it helps to see the exact request and response OkHttp sends and receives – headers, body, timing. An interceptor lets you inspect (or modify) every call passing through the client. The HttpLoggingInterceptor is a ready-made one that prints everything to Logcat (see android-logging-logcat.php for reading Logcat output in general).
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.build();
Timeouts
By default OkHttp uses a 10-second timeout for connecting, reading, and writing. You can tune these on the client builder – useful for slow networks or large recipe photo uploads:
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build();
Where OkHttp Fits
Your Code
Builds Request, reads Response
OkHttpClient
Connection pool, threads, interceptors
Network
Server API
Working with raw Request/Response objects and manual JSON parsing is fine, but it gets repetitive across many endpoints. The next lesson introduces Retrofit, which builds a type-safe, interface-based layer directly on top of the OkHttp client you just learned.