Create Upload Service for Amazon S3 in Android

Priyansh Kedia
Published in
3 min readFeb 14, 2022


Images are an essential part of any application. Uploading an image to the server, and then to a storage bucket like Amazon S3, can be time consuming. For this, Amazon provides their own SDK, to upload images directly to the S3 bucket.

In this blog, we will take a look at how we can create a background service to upload images to S3, and show a progress bar using RxJava.

Setting up the dependencies

Dependencies for RxJava and Amazon SDK

Add the above dependencies in your app-level build.gradle file.

Creating the File Status Class

Now we will go on and create a class for the status of our file upload.


This is a simple class which we will use to check for the upload status using the callbacks from S3 SDK.

Creating the PublishSubject instance

object LiveSubject {
val FILE_UPLOAD_FILE: PublishSubject<UploadFileStatus> = PublishSubject.create()

Create a new file and name it LiveSubject, and add the given code.

In the above code, you can see that we create an instance of PublishSubject and specify the data type that we are going to pass.

By definition, PublishSubject is

A Subject that emits items to currently subscribed Observers and terminal events to current.

RxJava helps you to simplify the implementation of complex concurrent behavior.

Creating the Upload Service Class

We start by creating a new file named UploadService.kt, which contains a class UploadService extending JobIntentService .

In this class, we will create a companion object (for static use), and add a simple function in there.

The enqueueWork will be called from our Activity/Fragment, to upload the image to the Amazon S3 bucket.

Now we will see the code in our UploadService

The onHandleWork is an override method, which handles the task in the background by default.

Inside onHandleWork, we just,

1. Get data from the intent
2. Get the image from the device
3. Create a file using the image
4. Extract the extension from the file

and send these parameters to the s3Upload function.

Inside the s3Upload function, we write some code directly taken from the SDK documentation, which requires us to provide our AWS_SECRET_KEY and AWS_ACCESS_KEY and our AWS_ENDPOINT.

The important thing to look at is the transferListener . This has three callbacks, onStateChanged, onProgressChanged and onError .

onStateChanged :- When the upload state changes from not started, to started and so on.
onProgressChanged :- Regularly invoked with the changing progress of the file upload
onError :- Invoked in case of error

Inside the onProgressChanged we get the current progress of our upload like

val status = (((current.toDouble() / total) * 100.0).toInt())                LiveSubject.FILE_UPLOAD_FILE.onNext(UploadFileStatus.FileStatus(status))

We get the status by dividing the current number of uploaded bytes by the total number of bytes.

So let’s say that our file is 1000 bytes, and currently, 500 bytes have even been uploaded, so our progress would be 50%.

We then emit the current progress in PublishSubject.

When the upload is complete, the onStateChanged is invoked, and we create our final file URL like

val url = "${secrets.s3BaseUrl}/$fileName.$extension"

where s3BaseUrl is the S3 bucket base URL.

Subscribing to RxJava subject

The above code shows how you can observe the RxJava subject, and show the progress in your progress bar, and get the final URL when the upload is complete.

Calling the UploadService

Now that we have created our UploadService, how do we call it?

val intent = Intent(this,
intent.putExtra(UploadService.IMAGE_URI, uri)
UploadService.enqueueWork(this, intent)

Using the above three lines, you can easily upload your image. The uri is the URI of the image that you pick from your device.

And this is all we need to do to write a clean and efficient code to upload files to the S3 bucket.

Demo App for S3 upload