Create Upload Service for Amazon S3 in Android
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
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, UploadService::class.java)
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.