Upload an image in background using WorkManager

We always think about which services to use for background image upload with better performance. Earlier we had AlarmManager, JobScheduler, FirebaseJobDispatcher for scheduling the background tasks. But the issues were, JobScheduler available only for API >= 21 and FirebaseJobDispatcher for backward compatibility. So I had to understand which method to use when.

But when I came across WorkManager library as part of the Android Jetpack component set. Moving forward, WorkManager replaces JobScheduler as Google’s recommended way to enqueue background tasks that are guaranteed to execute, I started liking it. I talked about what WorkManager is and why I should start considering WorkManager for scheduling tasks in Android applications.

  • Handles compatibility with different OS versions.
  • Follows system health best practices.
  • Supports asynchronous one-off and periodic tasks.
  • Supports chained tasks with input/output.
  • Lets you set constraints on when the task runs.
  • Guarantees task execution, even if the app or device restarts.

Implementing WorkManager in Android is easy.

Let get started with uploading an image in the background.

First we add the following dependencies in build.gradle file

dependencies { 
       def work_version = "2.3.4" 
       implementation "androidx.work:work runtime-ktx:$work_version" 
       //----- AWS dependencies 
       implementation 'com.amazonaws:aws-android-sdk-core:2.4.2'
       implementation 'com.amazonaws:aws-android-sdk-cognito:2.4.2'
       implementation 'com.amazonaws:aws-android-sdk-s3:2.4.2'
       implementation 'com.amazonaws:aws-android-sdk-ddb:2.4.2'
       implementation 'com.github.bumptech.glide:glide:4.8.0' 
}

First of all We will create the UploadWorker class by extending the Worker class, and override its doWork() method for background processing. When doWork() method is called by WorkManager, then it calls user defined method uploadImage(). I have used to AWS S3 service to upload image on Cloud.

class UploadWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {

        override fun doWork(): Result {
            // Upload the images.
            uploadImages()
            // Indicate whether the work finished successfully with the Result
            return Result.success()
        }

        private fun uploadImages() {
            try {
                // Upload images from camera and gallery url.
                var uploadImageURI = "/storage/emulated/0/Pictures/15062020155500.jpg";
                
                if (!TextUtils.isEmpty(uploadImageURI)) {
                    val file = File(uploadImageURI)
                    var transferUtility = AWSUtil.getTransferUtility(applicationContext)
                    var observer: TransferObserver = transferUtility.upload("Bucket-Name", file.name, file)
                    observer.setTransferListener(mUploadListener)
                }
            } catch (exeption: Exception) {
                exeption.printStackTrace()
            }
        }

        var mUploadListener = object : TransferListener {

            override fun onError(id: Int, e: Exception) {
                Log.e("ImageUpload", "Error during upload: " + id, e)
            }

            override fun onProgressChanged(id: Int, bytesCurrent: Long, bytesTotal: Long) {
                Log.d("ImageUpload", String.format("onProgressChanged: %d, total: %d, current: %d", id, bytesTotal, bytesCurrent))
            }

            override fun onStateChanged(id: Int, newState: TransferState) {
                if (newState == TransferState.COMPLETED) {
                    // Create uploaded image url
                    val imageURL: String = AWSConstants.S3_URL + "/" + "imageFilename"
                    Log.e("URL", "Upload: " + imageURL)
                }
            }
        }
    }

In our MainActivity.kt class, I’ve created a button, when user clicks on the button, then immediately UploadWorker class gets call and upload image.

    class MainActivity : AppCompatActivity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)

            setContentView(R.layout.activity_main)

            val uploadWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<UploadWorker>().build()
            btnStartUpload.setOnClickListener {
                WorkManager.getInstance(this@MainActivity).enqueue(uploadWorkRequest)
            }
        }
    }

That’s it!!.

We are done with all the configurations required to run our application.

Conclusion

Now run the application and see the Logcat for uploaded image url. I hope you get a clear idea about WorkManager.

If you face any issues, you can find complete source code here.

Happy coding!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.