evant / kotlin-inject

Dependency injection lib for kotlin
Apache License 2.0
1.29k stars 58 forks source link

How to inject WorkManager? #419

Open Monabr opened 3 months ago

Monabr commented 3 months ago

Hello.

I can't find how to inject WorkManager after searching the documentation.

Could you please tell me how to do this and update the documentation?

evant commented 3 months ago

You'll want to use a https://developer.android.com/reference/androidx/work/WorkerFactory to return your injected instances. Same pattern as what's suggested for fragments in the doc.

Monabr commented 3 months ago

@evant Could you please provide a more detailed explanation of how to do this using the kotlin-inject library? Unfortunately, I couldn't figure it out no matter how hard I tried.

AdriaBosch commented 3 months ago

Hi, I just migrated an Android project from Hilt to kotlin-inject. This is a summary of the code I used to inject WorkManager

@Inject
class MyWorker(
    @Assisted
    private val appContext: Context,
    @Assisted
    private val params: WorkerParameters,
    // Other dependencies
) : CoroutineWorker(appContext, params) {

    override suspend fun doWork() {}
}

interface WorkManagerComponent {

    @Provides
    @IntoMap
    fun provideMyWorkerEntry(
        workerCreator: (context: Context, params: WorkerParameters) -> MyWorker,
    ): Pair<KClass<out ListenableWorker>, (Context, WorkerParameters) -> MyWorker> {
        return Pair(MyWorker::class, workerCreator)
    }

   // other workers

    val MyWorkerFactory.provide: WorkerFactory
        @Provides get() = this

    @Singleton
    @Provides
    fun provideWorkManager(context: Context): WorkManager {
        return WorkManager.getInstance(context)
    }
}

@Inject
class MyWorkerFactory(
    private val workersMap: Map<KClass<out ListenableWorker>, (Context, WorkerParameters) -> ListenableWorker>
) : WorkerFactory() {

    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): ListenableWorker? {
            val entry = workersMap.entries.find {
                Class.forName(workerClassName).isAssignableFrom(it.key.java)
            }
            val workerCreator = entry?.value ?: return null
            return workerCreator(appContext, workerParameters)
    }
}

Then provide WorkerFactory to your application class:

class MyApplication : Application(), Configuration.Provider {

    private lateinit var workerFactory: WorkerFactory

    override fun onCreate() {
        super.onCreate()

        // create your application component

        workerFactory = appComponent.workerFactory
    }

    override fun getWorkManagerConfiguration(): Configuration {
        return Configuration.Builder()
            .setWorkerFactory(workerFactory)
            .build()
    }
}

And don't forget to disable WorkManager initialization from your Manifest.

I hope it helps.