Last active
December 1, 2023 20:01
-
-
Save luanmm/85dd8217ed3f7384e6bab075a8ab7a61 to your computer and use it in GitHub Desktop.
Android WorkManager dependency injection (with Dagger)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
...> | |
<application | |
...> | |
... | |
<provider | |
android:name="androidx.work.impl.WorkManagerInitializer" | |
android:authorities="<your-app-package>.workmanager-init" | |
android:enabled="false" | |
android:exported="false" | |
tools:replace="android:authorities" /> | |
</application> | |
</manifest> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.work.Worker | |
object AndroidWorkerInjection { | |
fun inject(worker: Worker) { | |
val application = worker.applicationContext | |
if (application !is HasWorkerInjector) { | |
throw RuntimeException( | |
"${application.javaClass.canonicalName} does not implement ${HasWorkerInjector::class.java.canonicalName}") | |
} | |
val workerInjector = (application as HasWorkerInjector).workerInjector() | |
checkNotNull(workerInjector) { "${application.javaClass}.workerInjector() return null" } | |
workerInjector.inject(worker) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.work.Worker | |
import dagger.Module | |
import dagger.android.AndroidInjector | |
import dagger.multibindings.Multibinds | |
@Module | |
abstract class AndroidWorkerInjectionModule { | |
@Multibinds | |
abstract fun workerInjectorFactories(): Map<Class<out Worker>, AndroidInjector.Factory<out Worker>> | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.work.Configuration | |
import androidx.work.WorkManager | |
import androidx.work.Worker | |
import dagger.android.AndroidInjector | |
import dagger.android.DispatchingAndroidInjector | |
import dagger.android.support.DaggerApplication | |
import javax.inject.Inject | |
class App : DaggerApplication(), HasWorkerInjector { | |
@Inject | |
lateinit var workerInjector: DispatchingAndroidInjector<Worker> | |
override fun workerInjector(): AndroidInjector<Worker> = workerInjector | |
override fun applicationInjector(): AndroidInjector<out DaggerApplication> = | |
DaggerAppComponent.builder().create(this) | |
override fun onCreate() { | |
super.onCreate() | |
initWorkManager() | |
} | |
private fun initWorkManager() { | |
val config = Configuration.Builder() | |
.setWorkerFactory(DaggerWorkerFactory()) // Overrides default WorkerFactory | |
.build() | |
WorkManager.initialize(this, config) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dagger.Component | |
import dagger.android.AndroidInjector | |
import dagger.android.support.AndroidSupportInjectionModule | |
import javax.inject.Singleton | |
@Singleton | |
@Component(modules = [ | |
AndroidSupportInjectionModule::class, | |
AndroidWorkerInjectionModule::class, // Worker injection module referenced in the AppComponent | |
AppModule::class | |
]) | |
interface AppComponent : AndroidInjector<App> { | |
@Component.Builder | |
abstract class Builder : AndroidInjector.Builder<App>() | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context | |
import androidx.work.ListenableWorker | |
import androidx.work.Worker | |
import androidx.work.WorkerFactory | |
import androidx.work.WorkerParameters | |
class DaggerWorkerFactory : WorkerFactory() { | |
override fun createWorker( | |
appContext: Context, | |
workerClassName: String, | |
workerParameters: WorkerParameters | |
): ListenableWorker? { | |
val constructor = Class.forName(workerClassName) | |
.asSubclass(Worker::class.java) | |
.getDeclaredConstructor(Context::class.java, WorkerParameters::class.java) | |
return constructor.newInstance(appContext, workerParameters) | |
.apply { AndroidWorkerInjection.inject(this) } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.work.Worker | |
import dagger.android.AndroidInjector | |
interface HasWorkerInjector { | |
fun workerInjector(): AndroidInjector<Worker> | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context | |
import androidx.work.Data | |
import androidx.work.Worker | |
import androidx.work.WorkerParameters | |
import javax.inject.Inject | |
class SampleWorker(context: Context, params: WorkerParameters) | |
: Worker(context, params) { | |
@Inject | |
lateinit var sampleRepository: SampleRepository | |
override fun doWork(): Result { | |
val myData = sampleRepository.getMyData() | |
// ... | |
} | |
companion object { | |
const val TAG = "SampleWorker" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello, people!
Sorry about the long delay in my reply for this gist.
It was created as a first try to handle dependency injection in WorkManager. But it was implemented even before the stable release of the WorkManager. So it is not really updated and may not work in the newer library version.
I really didn't liked the way WorkManager was designed without this look for dependency injection. But now the recommended way to do it is something like this tutorial: https://proandroiddev.com/dagger-2-setup-with-workmanager-a-complete-step-by-step-guild-bb9f474bde37. It uses AssistedInject library to make things work more easily.
Personally, I think that may have a better way to instantiate workers without using AssistedInject and doing the things in a simplified way (as I tried at first). But my knowledge about the inner structure of Dagger does not allow me to design a better solution. So, for now, I am using the recommended tutorial in my personal projects aswell.
Sorry for disappointing, if it is the case who looked for someting more simplified, but currently I don't know a better way to do it. If someone knows, feel free to share or post an updated gist.
Thank you all for your considerations and for helping each other!
Best regards.