Android Kotlin : File upload tutorial (Images/photos)

Parthan Parth
3 min readJun 19, 2021

This tutorial will help you to understand and write code for file uploading in android using kotlin. We will use retrofit library for this process, which makes this much more easier.

This will teach you to upload a file from camera as well as from your android gallery.

For uploading any image file from android phone will require a path of that image. If the path is available, then the file uploading process will be easier. When we take a photo using camera, the photo won’t be saved until we accept the clicked image. So getting that file path is difficult. Instead we will only get URI for that image. URI is also path to that image, but its not actual path. We need to convert that URI into actual path for this process.

Copy this class into a separate kotlin class, which helps to convert URI into actual path.

class URIPathHelper {

fun getPath(context: Context, uri: Uri): String? {
val isKitKatorAbove = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT

// DocumentProvider
if (isKitKatorAbove && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(“:”.toRegex()).toTypedArray()
val type = split[0]
if (“primary”.equals(type, ignoreCase = true)) {
return Environment.getExternalStorageDirectory().toString() + “/” + split[1]
}

} else if (isDownloadsDocument(uri)) {
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(Uri.parse(“content://downloads/public_downloads”), java.lang.Long.valueOf(id))
return getDataColumn(context, contentUri, null, null)
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(“:”.toRegex()).toTypedArray()
val type = split[0]
var contentUri: Uri? = null
if (“image” == type) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if (“video” == type) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if (“audio” == type) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
val selection = “_id=?”
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
}
} else if (“content”.equals(uri.scheme, ignoreCase = true)) {
return getDataColumn(context, uri, null, null)
} else if (“file”.equals(uri.scheme, ignoreCase = true)) {
return uri.path
}
return null
}

fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?): String? {
var cursor: Cursor? = null
val column = “_data”
val projection = arrayOf(column)
try {
cursor = context.getContentResolver().query(uri!!, projection, selection, selectionArgs,null)
if (cursor != null && cursor.moveToFirst()) {
val column_index: Int = cursor.getColumnIndexOrThrow(column)
return cursor.getString(column_index)
}
} finally {
if (cursor != null) cursor.close()
}
return null
}

fun isExternalStorageDocument(uri: Uri): Boolean {
return “com.android.externalstorage.documents” == uri.authority
}

fun isDownloadsDocument(uri: Uri): Boolean {
return “com.android.providers.downloads.documents” == uri.authority
}

fun isMediaDocument(uri: Uri): Boolean {
return “com.android.providers.media.documents” == uri.authority
}
}

Next, in the activity class follow my code

val REQUEST_CODE = 200

var PERMISSION_ALL = 1

// we require two main permissions for accessing camera and external storage. We will use this as runtime permission.

var PERMISSIONS = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
)

var selectedImageUri: Uri? = null
var cameraUri: Uri? = null

if (!hasPermissions(this, *PERMISSIONS)) {
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
}

fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}

To open camera and get image from it use the following code.

file_upload_button.setOnClickListener {

var values = ContentValues()
values.put(MediaStore.Images.Media.TITLE, “MyPicture”)
values.put(
MediaStore.Images.Media.DESCRIPTION,
“Photo taken on “ + System.currentTimeMillis()
)
cameraUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

//this is used to open camera and get image file
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri);
startActivityForResult(cameraIntent, REQUEST_CODE)
}

To select image from gallery

pick_from_gallery_layout.setOnClickListener {
val pickImageIntent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.INTERNAL_CONTENT_URI
)
pickImageIntent.type = “image/*”
val mimeTypes = arrayOf(“image/jpeg”, “image/png”)
pickImageIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
startActivityForResult(pickImageIntent, IMAGE_PICK_CODE)
}

TO RECEIVE INTENT DETAILS use these functions in your activity file.

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE) {


Log.i(“CameraCapture”, cameraUri.toString())

selectedImageUri = cameraUri
Log.i(“ImagePICK”, selectedImageUri.toString())
uploadImage()
}

if (resultCode == Activity.RESULT_OK && requestCode == IMAGE_PICK_CODE && data != null) {

selectedImageUri = data?.data
Log.i(“ImagePICK”, selectedImageUri.toString())

uploadImage()

}
}

UPLOAD IMAGE API CONTENT — USAGE OF MULTIPART instead of FORM-DATA- uploadImage() function

Use the selected image URI to create a multipartBody and use it to upload the file

val uriPathHelper = URIPathHelper()
val filePath = uriPathHelper.getPath(this, selectedImageUri!!)
Log.i(“FilePath”, filePath.toString())
val file = File(filePath)
val requestFile: RequestBody =
RequestBody.create(MediaType.parse(“multipart/form-data”), file)
val multiPartBody = MultipartBody.Part.createFormData(“file”, file.name, requestFile)

Retrofit interface for calling api

@Headers(
“Accept:application/json”
)
@Multipart
@POST(“url”)
fun uploadImage(
@Part image: MultipartBody.Part,

): Call<UserDefinedResponse>

That’s it! Thanks guys

--

--

Parthan Parth
Parthan Parth

Written by Parthan Parth

Working as Junior Software engineer at Tech Creations pty ltd.

Responses (1)