Search code examples
androidkotlinlambdaandroid-workmanager

How can I pass a Lambda to the MyWorkManager class?


I'm using kotlin for android and I'm trying to create a generic Worker class in which I can pass a lambda which can be called from doWork() method.

class BaseWorker(val context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {

        //Passed from the activity while creating the work request
        someLambda()

        return Result.success()
    }
}

The problem is I am not instantiating the BaseWorker class by calling the constructor. Is it possible to pass the Lambda using setInputData() of OneTimeWorkRequestBuilder class.

I referred How to pass the worker parameters to WorkManager class where the constructor of the class is being called which I think is not the right way.


Solution

  • The Data class in WorkManager it's only intended for base types and their arrays. You cannot use it to pass a lamba.

    A possible solution is to customize WorkManager's initialization, as explained in the documentation, and use a custom WorkerFactory to add a parameter to the constructor that you can use to retrieve the lambda. Keep in mind that you are configuring WorkManager just once, at initialization time. This means that you can pass directly the lambda as the additional parameter, but it will not be possible to customize it for each WorkRequest.

    Depending on what you want to achieve exactly, something similar can be used as a starting point:

    // provide custom configuration
    val config = Configuration.Builder()
            .setMinimumLoggingLevel(android.util.Log.INFO)
            .setWorkerFactory(MyWorkerFactory(lambda))
            .build()
    
    //initialize WorkManager
    WorkManager.initialize(this, config)
    
    val workManager = WorkManager.getInstance()
    

    And then have your WorkerFactory:

    class MyWorkerFactory(private val lambda: Unit) : WorkerFactory() {
        override fun createWorker(appContext: Context,
                              workerClassName: String,
                              workerParameters: WorkerParameters): MyWorker {
    
            return MyWorker(appContext, workerParameters, lambda)
        }
    }
    

    You can then have your worker that use the new constructor:

    class MyWorker(val context: Context, workerParams: WorkerParameters, private val lambda: Unit) : Worker(context, workerParams) {
        override fun doWork(): Result {
            //Passed from the WorkManager's configuration
            lambda()
    
            return Result.success()
        }
    }
    

    Remember to disable the default WorkManager initialization adding to the AndroidManifest.xml:

    <provider
              android:name="androidx.work.impl.WorkManagerInitializer"
              android:authorities="${applicationId}.workmanager-init"
              tools:node="remove" />