How to get live data from WorkManager in Android
Asked Answered
S

3

6

I am trying to make an API call from the doWork() method of WorkManager. I receive MutableLiveData with a list from the response. How do I set this complex object as an output from WorkManager?

Please find below the implementation for the same:

class FetchWorkManager(context: Context, params: WorkerParameters): Worker(context, params) {
    var postInfoLiveData: LiveData<List<PostInfo>> = MutableLiveData()

    @SuppressLint("RestrictedApi")
    override fun doWork(): Result {
        fetchInfoFromRepository()
        // Setting output data
        val data = Data.Builder()
            .putAll(postInfoLiveData)
            //.put("liveData", postInfoLiveData)
            .build()
        return Result.success(data)
    }


    fun fetchInfoFromRepository() {
        val retrofitRepository = RetrofitRepository()
        postInfoLiveData = retrofitRepository.fetchPostInfoList()
    }
}

Can anyone help me in resolving this issue?

Sartain answered 22/1, 2020 at 12:46 Comment(2)
You can store response list data in Room Database even if your app is running out from backgroundSight
But how to set LiveData received from web service in doWork() method. For primitive objects it is fine. Is there a way to set custom objects likes LiveData as output dataSartain
M
4

i am not sure but it should be like this :)

workManager?.getWorkInfoByIdLiveData(oneTimeWorkRequest.id)
                ?.observe(this, Observer {
                    if (it?.state == null)
                        return@Observer
                    when (it.state) {
                        State.SUCCEEDED -> {
                            val successOutputData = it.outputData

                        }
                        State.FAILED -> {
                            val failureOutputData = it.outputData

                        }
                    }
                })
Milinda answered 22/1, 2020 at 13:11 Comment(1)
But how to set LiveData received from web service in doWork() method. For primitive objects it is fine. Is there a way to set custom objects likes LiveData as output dataSartain
D
2

It is not intended behaviour to return result from Worker with LiveData member. The result from the Worker should be returned as a return value of startWork method. To construct Result object with some data ListenableWorker.Result.success method can be used.

const val WORKER_RESULT_INT = "WORKER_RESULT_INT"

class WorkerWithOutput(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        // do some work
        return Result.success(Data.Builder().putInt(WORKER_RESULT_INT, 123).build())
    }
}

And to get this data from outside one of getWorkInfoXXX methods should be used.

fun getResult(context: Context, owner: LifecycleOwner, id: UUID) {
    WorkManager.getInstance(context)
            .getWorkInfoByIdLiveData(id)
            .observe(owner, Observer {
                if (it.state == WorkInfo.State.SUCCEEDED) {
                    val result = it.outputData.getInt(WORKER_RESULT_INT, 0)
                    // do something with result
                }
            })
}

Activity or fragment can be passed as LifecycleOwner (depending on your case). WorkRequest.getId is used to get id of the work.

It is worth noting that there is ListenableWorker.setProgressAsync which also can be useful in such circumstances.

Diella answered 22/1, 2020 at 13:6 Comment(3)
But how to set LiveData received from web service in doWork() method. For primitive objects it is fine. Is there a way to set custom objects likes LiveData as output dataSartain
@Sartain Unfortunately it's not possible to put LiveData oject into Data. It is not even possible to put Parcleable into Data (unlike into Bundle). Data class is designed so that it can be persisted into database - this requirement restricts the set of data types which can be put into Data object.Diella
WorkManager is not desinged for querying data, it is intended for background task independent of UI workflow. This link may help to better understand its purposes. For querying data in background it's better to use RxJava or kotlin coroutines.Diella
P
0

I am not sure if this would work since I have not tried it yet. and I know it is a late answer but I would encourage you to try to use CoroutineWorker as below:

class MyWorker(context: Context, params: WorkerParameters):
    CoroutineWorker(context, params){
    override suspend fun doWork(): Result {

      val data = withContext(Dispatchers.IO) {
         // you can make network request here (best practice?)
         return@withContext fetchInfoFromRepository()
         // make sure that fetchInfoFromRepository() returns  LiveData<List<PostInfo>>
      }
    
      /* Then return it as result with a KEY (DATA_KEY) to use in UI. */
      val result = workDataOf(DATA_KEY to data)
      return Result.success(result)
   }
}

ref: https://developer.android.com/topic/libraries/architecture/workmanager/advanced/coroutineworker

Paralysis answered 31/12, 2020 at 14:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.