Search code examples
androidkotlinandroid-lifecycle

Android: Kotlin: running tasks upon app closing


While a user moves around my app I collect key events in a list. When the user quits the app I want to:

  1. write that list to a file; and
  2. upload that file to the cloud for analysis on the backend

I put everything in a function and unit-tested, and it works fine so long as the app is still active. But:

  1. calling the function from the MainActivity onStop() doesn't upload the file to the cloud (it is written to the device successfully)
  2. ditto onPause()
  3. I tried to send a completableDeferred to the function and .await for it, but that didn't help either (I used a coroutine scope initiated by MainActivity).

I've heard before the edict "Though shalt not mess with the lifecycle events", so I guess this is a confirmation...

How do you suggest I accomplish this (upload the file to the cloud when the user quits the app)? It doesn't need to be immediate, it just needs to happen eventually.

Thank you!


Solution

  • Maybe try to use WorkManager. It can work in background

    class FileUploadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    
        override fun doWork(): Result {
            val filePath = inputData.getString("filePath") ?: return Result.failure()
    
            return try {
                val file = File(filePath)
                if (file.exists()) {
                    uploadToCloud(file)
                    Result.success()
                } else {
                    Result.failure()
                }
            } catch (e: Exception) {
                e.printStackTrace()
                Result.retry()
            }
        }
    
        private fun uploadToCloud(file: File) {
            // ...
        }
    }
    

    And start it from Activity onStop

    override fun onStop() {
        super.onStop()
    
        val filePath = saveEventsToFile()
    
        val data = Data.Builder()
            .putString("filePath", filePath)
            .build()
    
        val uploadWorkRequest = OneTimeWorkRequestBuilder<FileUploadWorker>()
            .setInputData(data)
            .build()
    
        WorkManager.getInstance(applicationContext).enqueue(uploadWorkRequest)
    }
    
    private fun saveEventsToFile(): String {
        val filePath = "${filesDir.path}/events.json"
        return filePath
    }