Android Development
POST Method
Data Transmission
Mobile Programming
Android Networking

Sending POST data in Android

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Sending POST data in Android is really an HTTP client question. You need to choose the request body format, use the right headers, and make sure the network call runs off the main thread. The API surface you choose, such as OkHttp, Retrofit, or lower-level HttpURLConnection, mostly changes ergonomics rather than the underlying rules.

In modern Android projects, OkHttp or Retrofit are usually the practical defaults. HttpURLConnection is still worth understanding because it shows the raw mechanics clearly, but most production apps do not need to build every request at that level.

Understand What the Server Expects

A POST request can carry different kinds of bodies:

  • 'application/json'
  • 'application/x-www-form-urlencoded'
  • 'multipart/form-data'
  • raw binary data

If the server expects JSON and you send form fields, the request will fail even though the method is technically POST. Before writing client code, confirm the endpoint contract:

  • URL
  • headers
  • body format
  • authentication requirements

Without that, debugging becomes guesswork.

A Simple JSON POST With OkHttp

OkHttp is a clean direct HTTP client for Android. A basic JSON POST looks like this:

kotlin
1import okhttp3.MediaType.Companion.toMediaType
2import okhttp3.OkHttpClient
3import okhttp3.Request
4import okhttp3.RequestBody.Companion.toRequestBody
5
6val client = OkHttpClient()
7
8val json = """{"name":"Ava","role":"admin"}"""
9val body = json.toRequestBody("application/json; charset=utf-8".toMediaType())
10
11val request = Request.Builder()
12    .url("https://api.example.com/users")
13    .post(body)
14    .build()

That covers the essential pieces:

  • a URL
  • a request body
  • a Content-Type
  • the POST method

You would then execute that request from a background thread or coroutine.

Running the Call Off the Main Thread

Android does not allow network activity on the main thread in normal app code. A coroutine-based wrapper is a clean modern option:

kotlin
1import kotlinx.coroutines.Dispatchers
2import kotlinx.coroutines.withContext
3
4suspend fun createUser(client: OkHttpClient): Int = withContext(Dispatchers.IO) {
5    val json = """{"name":"Ava","role":"admin"}"""
6    val body = json.toRequestBody("application/json; charset=utf-8".toMediaType())
7
8    val request = Request.Builder()
9        .url("https://api.example.com/users")
10        .post(body)
11        .build()
12
13    client.newCall(request).execute().use { response ->
14        response.code
15    }
16}

The important part is not the coroutine syntax itself. It is the fact that the blocking HTTP work happens in an IO context rather than on the UI thread.

Retrofit for API-Oriented Apps

If the app talks to a defined REST API, Retrofit usually gives a cleaner structure than building requests manually.

kotlin
1import retrofit2.Response
2import retrofit2.http.Body
3import retrofit2.http.POST
4
5data class UserRequest(
6    val name: String,
7    val role: String
8)
9
10interface ApiService {
11    @POST("users")
12    suspend fun createUser(@Body request: UserRequest): Response<Unit>
13}

Retrofit is especially useful when your app has many endpoints because it centralizes request definitions and serialization rules instead of scattering HTTP details across activities or view models.

HttpURLConnection Still Explains the Basics

If you want to see the protocol mechanics directly, HttpURLConnection is still a valid learning tool:

java
1URL url = new URL("https://api.example.com/data");
2HttpURLConnection connection = (HttpURLConnection) url.openConnection();
3connection.setRequestMethod("POST");
4connection.setDoOutput(true);
5connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");

From there, you write the request body to the output stream and read the response code. This is lower-level than OkHttp, but it makes the basics explicit.

Handle Responses and Errors Explicitly

Do not stop at "the request was sent." Check the response code and, when needed, the error body. A server returning 400, 401, or 500 is giving you useful information.

Good POST handling usually includes:

  • inspecting the HTTP status code
  • logging or surfacing useful error details
  • handling timeouts and retries appropriately
  • keeping secrets out of logs

That is often more important than the choice between one client library and another.

Common Pitfalls

The biggest mistake is doing the request on the main thread. Even correct HTTP code becomes broken Android code if it blocks the UI.

Another common issue is sending the wrong Content-Type. The body may look fine locally, but the server will still reject it if the header does not match the actual encoding.

Developers also often ignore response details and only check whether an exception was thrown. Many API errors are communicated through ordinary HTTP responses, not transport failures.

Finally, avoid manually concatenating JSON strings once payloads become nontrivial. Use a serializer or a Retrofit converter instead of hand-building large request bodies.

Summary

  • Sending POST data in Android means choosing the right body format, headers, and client.
  • OkHttp is a strong default for direct HTTP requests.
  • Retrofit is often cleaner for structured REST APIs.
  • Keep network calls off the main thread, usually with coroutines or another background mechanism.
  • Match Content-Type and body shape to the server contract, then inspect response codes carefully.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.