I want to use a Worker in my Android app (pure Kotlin) to so some background work. I'm using Hilt for dependency injection, but I'm facing some problems when I need to pass a custom object to the Worker.
My code is as follows:
@HiltWorker
class BackgroundWorker @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
val mockClass: MockClass
) : CoroutineWorker(appContext, workerParams) {
init {
Log.d("deb", "Worker: Initiated")
}
override suspend fun doWork(): Result {
Log.d("deb", "Worker: Doing work!")
return Result.success()
}
}
And my MockClass is:
@Module
@InstallIn(SingletonComponent::class)
object MockModule {
@Singleton
@Provides
fun provideMockClass(): MockClass = MockClass()
}
class MockClass{}
Inside my onCreate
function in my main activity I call:
WorkManager.getInstance(applicationContext).enqueue(
OneTimeWorkRequestBuilder<BackgroundWorker>().build()
)
to initiate the worker and call de doWork
function, but when I start the app, I don't see the logs
and the AppInspector
shows "Failed" as the WorkerStatus.
I know that my Application
class (annotated with @HiltAndroidApp
) is correctly configured (using WorkerFactory
, etc.) and the AndroidManifest.xml
is well configured (using the provider
tag, etc.), because when I comment out the line:
val mockClass: MockClass
then I see the logs
from inside my Worker
(both of them, the init
and the doWork
one). So it works perfectly fine! But when I uncomment the line (so that the mockClass
object is passed to the worker), the worker is not able to initiate.
Just for completion, here is my Manifest
:
<application
...
android:name=".MyApplication">
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove">
</provider>
...
</>
, Application
class:
@HiltAndroidApp
class MyApplication : Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: HiltWorkerFactory
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
}
, the dependencies I'm using:
[verions]
hiltCommon = "1.2.0"
workerRuntimeKtx = "2.10.0"
hilt = "2.55"
hilt-work = "1.2.0"
kotlin = "2.1.0"
ksp = "2.1.0-1.0.29"
[libraries]
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
hilt-work = { group = "androidx.hilt", name = "hilt-work", version.ref = "hilt-work" }
androidx-hilt-common = { group = "androidx.hilt", name = "hilt-common", version.ref = "hiltCommon" }
androidx-worker-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workerRuntimeKtx" }
[plugins]
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
kotlin-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
in module-level build.gradle
:
plugins{
...
alias(libs.plugins.hilt)
alias(libs.plugins.kotlin.ksp)
}
dependencies{
implementation(libs.androidx.worker.runtime.ktx)
implementation(libs.hilt.android)
implementation(libs.hilt.work)
implementation(libs.androidx.hiltmon)
ksp(libs.hiltpiler){
exclude("META-INF/gradle/incremental.annotation.processors")
}
}
and in project-level build.gradle
:
plugins{
alias(libs.plugins.kotlin.ksp) apply false
alias(libs.plugins.hilt) apply false
}
I think my problem is somehow related to the DI and Hilt, but I cannot figure out what it is. I use Hilt
for dependency injection on other parts in my app, and they work okay.
I want to use a Worker in my Android app (pure Kotlin) to so some background work. I'm using Hilt for dependency injection, but I'm facing some problems when I need to pass a custom object to the Worker.
My code is as follows:
@HiltWorker
class BackgroundWorker @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
val mockClass: MockClass
) : CoroutineWorker(appContext, workerParams) {
init {
Log.d("deb", "Worker: Initiated")
}
override suspend fun doWork(): Result {
Log.d("deb", "Worker: Doing work!")
return Result.success()
}
}
And my MockClass is:
@Module
@InstallIn(SingletonComponent::class)
object MockModule {
@Singleton
@Provides
fun provideMockClass(): MockClass = MockClass()
}
class MockClass{}
Inside my onCreate
function in my main activity I call:
WorkManager.getInstance(applicationContext).enqueue(
OneTimeWorkRequestBuilder<BackgroundWorker>().build()
)
to initiate the worker and call de doWork
function, but when I start the app, I don't see the logs
and the AppInspector
shows "Failed" as the WorkerStatus.
I know that my Application
class (annotated with @HiltAndroidApp
) is correctly configured (using WorkerFactory
, etc.) and the AndroidManifest.xml
is well configured (using the provider
tag, etc.), because when I comment out the line:
val mockClass: MockClass
then I see the logs
from inside my Worker
(both of them, the init
and the doWork
one). So it works perfectly fine! But when I uncomment the line (so that the mockClass
object is passed to the worker), the worker is not able to initiate.
Just for completion, here is my Manifest
:
<application
...
android:name=".MyApplication">
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove">
</provider>
...
</>
, Application
class:
@HiltAndroidApp
class MyApplication : Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: HiltWorkerFactory
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
}
, the dependencies I'm using:
[verions]
hiltCommon = "1.2.0"
workerRuntimeKtx = "2.10.0"
hilt = "2.55"
hilt-work = "1.2.0"
kotlin = "2.1.0"
ksp = "2.1.0-1.0.29"
[libraries]
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
hilt-work = { group = "androidx.hilt", name = "hilt-work", version.ref = "hilt-work" }
androidx-hilt-common = { group = "androidx.hilt", name = "hilt-common", version.ref = "hiltCommon" }
androidx-worker-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workerRuntimeKtx" }
[plugins]
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
kotlin-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
in module-level build.gradle
:
plugins{
...
alias(libs.plugins.hilt)
alias(libs.plugins.kotlin.ksp)
}
dependencies{
implementation(libs.androidx.worker.runtime.ktx)
implementation(libs.hilt.android)
implementation(libs.hilt.work)
implementation(libs.androidx.hiltmon)
ksp(libs.hiltpiler){
exclude("META-INF/gradle/incremental.annotation.processors")
}
}
and in project-level build.gradle
:
plugins{
alias(libs.plugins.kotlin.ksp) apply false
alias(libs.plugins.hilt) apply false
}
I think my problem is somehow related to the DI and Hilt, but I cannot figure out what it is. I use Hilt
for dependency injection on other parts in my app, and they work okay.
1 Answer
Reset to default 1Your Gradle setup for Hilt is off.
In your version catalog you need to replace the two libraries
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
androidx-hilt-common = { group = "androidx.hilt", name = "hilt-common", version.ref = "hiltCommon" }
with these:
hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
androidx-hilt-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hilt-work" }
Now, in your gradle file replace
implementation(libs.androidx.hiltmon)
ksp(libs.hiltpiler){
exclude("META-INF/gradle/incremental.annotation.processors")
}
accordingly with
ksp(libs.hilt.androidpiler)
ksp(libs.androidx.hiltpiler)
The Hilt injection should now work without issues, even for the WorkManager.