Uploading images from an Android app to a web service is common in modern mobile applications — whether it’s user avatars, posts, or content uploads. When working without third‑party libraries like Retrofit or Volley, you can use the standard HttpURLConnection with a multipart/form‑data POST request to send image files directly to your server.
This updated guide on javatechig.com demonstrates how to construct and send a multipart image upload request using HttpURLConnection, handle server response, and follow best practices in both Kotlin and Java.
What Is HttpURLConnection Upload?
HttpURLConnection is a core Java API to make HTTP requests. To upload an image:
- You build a multipart/form‑data request
- Include boundary markers to separate parts
- Write file bytes to the connection output stream
- Read server response afterward
This method works without external libraries and gives fine‑grained control over the upload process.
Permissions You Need
In your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
Optional (for reading images from storage):
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Always request runtime permissions for storage on Android 6.0+.
Multipart Upload Overview
When uploading files with HttpURLConnection:
- Use boundary strings to split fields
- Set
Content-Typeheader tomultipart/form-data; boundary=… - Write both form fields and file data
This follows the RFC 2387 multipart standard used by HTML form uploads.
Kotlin Example: Upload Image
fun uploadImage(imagePath: String, uploadUrl: String) {
val boundary = "*****" + System.currentTimeMillis() + "*****"
val lineEnd = "\r\n"
val twoHyphens = "--"
val file = File(imagePath)
val fileInputStream = FileInputStream(file)
val url = URL(uploadUrl)
val connection = url.openConnection() as HttpURLConnection
connection.apply {
doInput = true
doOutput = true
useCaches = false
requestMethod = "POST"
setRequestProperty("Connection", "Keep-Alive")
setRequestProperty(
"Content-Type",
"multipart/form-data;boundary=$boundary"
)
}
val outputStream = DataOutputStream(connection.outputStream)
// Write form header
outputStream.writeBytes(twoHyphens + boundary + lineEnd)
outputStream.writeBytes("Content-Disposition: form-data; name=\"image\"; filename=\"${file.name}\"$lineEnd")
outputStream.writeBytes("Content-Type: image/jpeg$lineEnd")
outputStream.writeBytes(lineEnd)
// Write file
val buffer = ByteArray(1024)
var bytesRead: Int
while (fileInputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
}
outputStream.writeBytes(lineEnd)
// End request
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd)
outputStream.flush()
fileInputStream.close()
outputStream.close()
val responseCode = connection.responseCode
val response = connection.inputStream.bufferedReader().use { it.readText() }
Log.d("UploadStatus", "Response Code: $responseCode")
Log.d("UploadStatus", "Response: $response")
}
This uploads the image file by writing raw bytes in multipart form.
Java Example: Upload Image
public void uploadImage(String imagePath, String uploadUrl) {
String boundary = "*****" + System.currentTimeMillis() + "*****";
String lineEnd = "\r\n";
String twoHyphens = "--";
File file = new File(imagePath);
try {
FileInputStream fis = new FileInputStream(file);
URL url = new URL(uploadUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty(
"Content-Type",
"multipart/form-data;boundary=" + boundary
);
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"image\"; filename=\""
+ file.getName() + "\"" + lineEnd);
outputStream.writeBytes("Content-Type: image/jpeg" + lineEnd);
outputStream.writeBytes(lineEnd);
int bytesRead;
byte[] buffer = new byte[1024];
while ((bytesRead = fis.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
outputStream.flush();
outputStream.close();
fis.close();
BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream())
);
String response = reader.readLine();
reader.close();
Log.d("UploadStatus", "Response: " + response);
} catch (Exception e) {
e.printStackTrace();
}
}
This code performs the same multipart file upload in pure Java.
Handling Server Response
After uploading, always check:
- Response code (e.g., 200 for success)
- Server JSON or text body
- Errors and exceptions
Reading the response ensures you know if the image saved correctly on backend.
Best Practices
1. Use Background Threads
Network operations should never run on the UI thread — use coroutines, AsyncTask, or thread pools to avoid ANR (Application Not Responding).
2. Use HTTPS
Always upload using HTTPS for security and privacy.
3. Check Response Codes
Handle different HTTP response codes (e.g., 400, 500) gracefully in your app UI.
4. Use Multipart Libraries When Possible
While HttpURLConnection works fine, modern projects often use libraries like Retrofit or OkHttp for cleaner, more maintainable code if complexity grows.
When to Use HttpURLConnection
HttpURLConnection is useful when:
- You want tight control over networking
- You are working without third‑party dependencies
- You need to customize request and headers manually
For most real‑world REST APIs, libraries like Retrofit are easier and safer.


