Closed droidrcc closed 4 years ago
in my case i inject it using inside doWork()
if (applicationContext is MyApp) {
(applicationContext as MyApp).userComponent.inject(this)
....
}
*MyApp is the application class name for my android app
We hope to have something soon. It likely will be in a new artifact (dagger-android-work
), plus support for @ContributesAndroidInjector
.
I know this is the wrong repo for this comment, but I wonder aloud why they couldn't have created a WorkerFactory class similar to ViewModelProvider.Factory for defining how to create Worker objects. Or something. I just really don't understand why Android framework classes can never have useful public constructors.
Hope they'll add it soon
@ronshapiro
hi there, do you have the roughly release date for this dagger-android-work
feature ?
There are a few things that need to change, let me document them here:
@ContributesAndroidInjector
supportAndroidWorkInjection.inject()
method, and probably also a map key.DaggerApplication
. The androidx
effort is fantastic in that it splits up a lot of things into individual libraries, but it complicates the approach we've taken thus far with DaggerApplication
. Specifically, someone could want a DaggerApplication
that has androidx.work
support but not androidx.fragment
support, and we shouldn't drag in any of those dependencies if we don't need to. This is reliant on the first two items, but also requires some thought about how to support the different flavors of android injection that we want/may want in the future. Codegen could help here too, but it may not be the best option.We also probably want to wait until the library is at least in beta, or at least we would have to release an "alpha" version of dagger-work.
Lastly, we need to modify our bazel configuration to pull in the android-work aars, hopefully that won't be too hard.
I made a gist of how I injected workers, its mostly the same as how other components are injected
https://gist.github.com/ferrerojosh/82bd92748f315155fa6a842f4ed64c82
Lots of boilerplate though
Hello guys,
Thanks to @ferrerojosh !
I made a Java version for that in case some people need it. https://gist.github.com/ThePredators/1702e79c5d3860f415c542da446420eb
Any updates on this now that androidx is released?
The Workers API is still in alpha
On Wed, Oct 3, 2018 at 1:03 AM Michael Limb notifications@github.com wrote:
Any updates on this now that androidx is released?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/dagger/issues/1183#issuecomment-426445967, or mute the thread https://github.com/notifications/unsubscribe-auth/AAwY3bgljVQVtVUcoHRw4FvNwWdv4vMbks5ug-LDgaJpZM4T-q7x .
Ah, good point.
I got throw a solution that's working in rather simple way. How good is that? Is there any pros/cons of it over the above discussed solutions (though above discussed ones didn't work for me). Answer: https://stackoverflow.com/a/52199645/5110536
And seems like WorkManager-alpha10 has support of DI , is it true?
WorkManager-alpha9 introduced WorkerFactory, which would allow you to use constructor injection with Dagger :D WorkManager-alpha10 introduced breaking changes, one of which is
The interface WorkerFactory and the concrete implementation DefaultWorkerFactory have been merged into an abstract class called WorkerFactory
Using WorkerFactory
certainly seems like the right way going forward. I wrote up more of an explanation on how it is actually used - https://stackoverflow.com/a/53377279/1654145
Thanks to @CDRussell and @ferrerojosh contributions, I was able to use DI in workers. The final code is a mix between the ideas exposed here - https://gist.github.com/luanmm/85dd8217ed3f7384e6bab075a8ab7a61.
I'm expecting, in the future, to be able to remove all of this custom code and see something like that directly in Dagger for Android. It would be the ideal scenario IMHO.
Hey all,
Looks like WorkManager was released to beta today: https://medium.com/androiddevelopers/introducing-workmanager-2083bcfc4712
From what I've read here: https://developer.android.com/jetpack/docs/release-notes#december_19_2018, it says:
This release contains no API changes; moving forward, WorkManager is expected to stay API stable until the next version unless there is a critical problem.
Does this mean no Dagger support is planning on being added? I realize this is probably not the ideal place to ask this question, but don't know where else to ask.
That's good. We still have some other dagger.android architecture cleanups to get done before we can get this, but I hope soon. We've been spending most of our efforts on buildperf recently
@ronshapiro okay, good to know it will be gotten to eventually. Thanks for the update!
@ronshapiro I just finished setting up constructor injection using multibinding for Worker
s using WorkerFactory.
Given the possibility of constructor injection, should members injection via AndroidInjection.inject(this)
still be considered/encouraged?
I wrote about my implementation here. Full working sample here.
I'd say members injection is always inferior to constructor injection. Fragments can be constructor injected as of 1.1+. Activities on 28+.
On Thu, Dec 20, 2018 at 7:56 PM Arunkumar notifications@github.com wrote:
@ronshapiro https://github.com/ronshapiro I just finished setting up constructor injection using multibinding for Workers using WorkerFactory https://developer.android.com/reference/androidx/work/WorkerFactory.
Given the possibility of constructor injection, should members injection via AndroidInjection.inject(this) still be considered/encouraged?
I wrote about my implementation here https://www.arunkumarsampath.in/dagger-recipes-illustrative-step-by-step-guide-to-achieve-constructor-injection-in-workmanager/. Full working sample here https://github.com/arunkumar9t2/dagger-workmanager.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/google/dagger/issues/1183#issuecomment-449193878, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEWV4NPwCAOW9xAoKCVla_BgaBd-wks5u7DHIgaJpZM4T-q7x .
Thank to Jake's presentation
We now able to perform constructor injection, like so:
class HelloWorldWorker @AssistedInject constructor(
@Assisted private val params: WorkerParameters,
private val appContext: Context,
private val foo: Foo
) : Worker(appContext, params) {
private val TAG = "HelloWorldWorker"
override fun doWork(): Result {
Log.d(TAG, "Hello world!")
Log.d(TAG, "Injected foo: $foo")
return Result.success()
}
@AssistedInject.Factory
interface Factory : ChildWorkerFactory<HelloWorldWorker>
}
No subcomponent needed
Fully working sample can be found here (also step by step guide in README) https://github.com/raiytu4/dagger-workmanager
@raiytu4 If going with AssistedInjection, it would be nice to have a @WorkerInject similar to @InflationInject to avoid this layers of factories. Ideally, it would be nice for WorkManager library to provide these and that goes to what Jake was talking about Dagger providing customization for libraries to provide modules.
I've (finally) just migrated to WM v1.0.0-beta01. Thanks to @raiytu4 for the nice example.
You can simplify it even further by just using the Context
which you're given in the Factory. I did that in: https://github.com/chrisbanes/tivi/pull/254
Seems AssistedInject
is easier compared to my subcomponent + multibinds approach.
Any reason the Context
could be anything other than the Application context? I thought this was a reasonable assumption to make, so ended up providing it from my root app component. The only param known at runtime was the workerParameters
.
@arunkumar9t2 You can dive into the WorkManager source code to find out, from what I see is that the Context
parameter is always your Application context.
@chrisbanes I checked out your pull, nice improvement you got there (remove the generic T), thank
interface ChildWorkerFactory {
fun create(context: Context, params: WorkerParameters): ListenableWorker
}
But, I don't get the part
You can simplify it even further by just using the
Context
which you're given in the Factory.
About the context, I basically do the same thing as you did in the beginning, then I realize that the context is just our application context. And the point is, we only need "assisted" for parameters that can only be known at runtime. So there is no point to "assisted" the context.
I disagree, I prefer to use whatever the factory passes me (if possible)
@chrisbanes Any reason not to have TiviWorkerFactory as singleton?
I've (finally) just migrated to WM v1.0.0-beta01. Thanks to @raiytu4 for the nice example.
You can simplify it even further by just using the
Context
which you're given in the Factory. I did that in: chrisbanes/tivi#254
Hey @chrisbanes. Thank you a lot of the example. I've been dealing with a few hours to set my WorkManager up like yours and I've done so but I'm stuck at a very weird bug. Would you have any idea on why this would happen?
When I do:
workManager.enqueue(wWorkRequest)
The Work runs (doWork() is called)
but when I do:
workManager.enqueueUniqueWork("Name", ExistingWorkPolicy.APPEND, wWorkRequest)
the work doesn't get start (doWork() is never called).
Prior to all my changes today such as AppWorkerFactory, ChildWorkerFactory, and all the changes you did in https://github.com/chrisbanes/tivi/pull/254, my enqueueUniqueWork used to work. So now injecting to the Worker classes via the way you've shown, somehow enqueueUniqueWork doesn't work. Only enqueue works.
Any help is appreciated! Thank you for your or anyone's time who can help out.
@iamjoin7 Weird. Have you stepped through the WorkerFactory to see if its createWorker()
is called?
@chrisbanes yes I had. createWorker()
actually does not get called.
Although, after inspecting it more, this may be a WorkManager issue. I've checked the db with stetho
and it seems the works are actually being saved, but never "run"ed
https://issuetracker.google.com/issues/121436946
It's quite weird how enqueueUniqueWork
was working injecting via AndroidWorkerInjector.inject(this)
but it's not via this @AssistedInject.Factory
🤔
Thank you for your time though @chrisbanes. I'm leaving my comment up in case someone else faces a simiar issue.
@iamjoin7 I tested it out, work fine on my part though, could you provide more detail? https://github.com/nlgtuankiet/dagger-workmanager/blob/iamjoin7-issue/app/src/main/java/com/sample/daggerworkmanagersample/MainActivity.kt
Thank you for the exclusive branch @nlgtuankiet :)
I've copy pasted your HelloWorldWorker
class and your sample code in my MainActivity
, and it worked 🤔.
So after messing around the last 15 mins. I tried running your HelloWorldWorker
with my MyWorker
class's TAG, via:
enqueueUniqueWork(MyWorker.TAG, ExistingWorkPolicy.APPEND...
and again, HelloWorldWorker
's doWork() never got called.
So somehow the "queue" for uniqueWorkName MyWorker.TAG
got stuck(?) and it since I've had previous works already in queue, the new ones I added via enqueueUniqueWork
where waiting for the first one to run.
So I went to my app's "App Info" and clicked "Clear Storage", emptying the databases. And ran my code again, and both HelloWorldWorker
and MyWorker
's doWork() got called.
So just to recap, the problem was the uniqueWorkName MyWorker.TAG
was frozen (not sure how that was possible). I'll be ignoring the issue now as I suspect(am hoping) it is one-time thing.
Apologies for taking your time @chrisbanes and @nlgtuankiet, really appreciate your help.
The worker api is stable now, will something like @ContributesAndroidInjector
be introduced in Dagger
There are already two working approaches discussed in this thread and both involve constructor injection instead of members injection. One is by using subcomponents and multibindings (link) and other one is using Square's AssistedInject (link).
IMHO, I don't think a @ContributesAndroidInjector
and AndroidInjection.inject(this)
solution is warranted anymore but I agree a working solution with simpler setup would be nice.
The fact that the above solutions require changing the configuration of the (singleton) WorkManager instance makes them unusable in libraries.
here is example for using worker and dagger with help of @ContributesAndroidInjector.
https://github.com/jega-ms/android-dagger2-mvp-rx/tree/master/app/src/main/java/dagger/worker
+1
+1
@nlgtuankiet can you share me a example of test for your worker with TestListenableWorkerBuilder
in this way?. Many thanks!!!
Srr, I did not find any test suite on it.
Given the possibility of constructor injection, should members injection via AndroidInjection.inject(this) still be considered/encouraged?
It's possible to use AndroidInjection.inject(this)
(sort of) over Worker
s since 2.20, where they removed the limitation that AndroidInjector
was only generated for Activity/Fragment/Service/ContentProvider/BroadcastReceiver.
Now you can do it as simple as
@ContributesAndroidInjector
abstract fun syncWorker(): SyncWorker
and
@Keep
class SyncWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
init {
val injector = context.applicationContext as HasAndroidInjector
injector.androidInjector().inject(this)
}
@Inject
lateinit var apiService: ApiService
This should be covered now with the Jetpack Hilt extension (https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager). Unfortunately for dagger.android, we likely won't be adding WorkManager support directly for that so I'm going to close this.
Hi, from latest Google I/O you just presented the new
androidx.work.Worker
class, part of the new WorkManager API.Since the
Worker
class is created by the framework (we only pass the Worker class type to theWorkManager
), how can we @inject fields into the Worker ? Do you intend to add a new AndroidInjection.inject() function that takes a worker as argument ?Thanks