Inject into Workers (androidx.WorkManager API)
From latest Google I/O you just presented the new `androidx.work.Worker` class, part of the new [WorkManager API](https://developer.android.com/topic/libraries/architecture/workmanager).
Since the `Worker` class is created by the framework (we only pass the Worker class type to the `WorkManager`), how can we @Inject fields into the Worker?
Let’s see how we @Inject fields into the worker?
Step 1: Create AndroidWorkerInjection.class Responsible for injecting dependencies into [WorkManager API](https://developer.android.com/topic/libraries/architecture/workmanager).
public class AndroidWorkerInjection {
public static void inject(Worker worker) {
//TODO : Check not null
Object application = worker.getApplicationContext();
if (!(application instanceof HasWorkerInjector)) {
throw new RuntimeException(
String.format(
"%s does not implement %s",
application.getClass().getCanonicalName(),
HasWorkerInjector.class.getCanonicalName()));
}
AndroidInjector<Worker> workerInjector =
((HasWorkerInjector) application).workerInjector();
checkNotNull(workerInjector, "%s.workerInjector() returned null", application.getClass());
workerInjector.inject(worker);
}
}
Step 2: Create a AndroidWorkerInjectionModule.class responsible for the binding same type of classes into one. In our case, all the class extends Worker class
@Module
public abstract class AndroidWorkerInjectionModule {
@Multibinds
abstract Map<Class<? extends Worker>, AndroidInjector.Factory<? extends Worker>>
workerInjectorFactories();
}
Step 3: Let's define our AppComponent.class and add above modules into it as below
@Singleton
@Component(modules = {
AppModule.class,
AndroidInjectionModule.class,
AndroidWorkerInjectionModule.class, // Worker injection module referenced in the AppComponent
WorkerModule.class}) // Worker Module
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(MyApplication myApplication);
}
Step 4: Define HasWorkerInjector as how we usually define Injectors for Activities HasActivityInjector, Services HasServiceInjector and etc..
public interface HasWorkerInjector {
AndroidInjector<Worker> workerInjector();
}
Step 5: let's implement HasWorkerInjector in the Application class. In our case Application is: MyApplication.class
public class MyApplication extends Application implements HasWorkerInjector{
@Inject
DispatchingAndroidInjector<Worker> workerDispatchingAndroidInjector;
private AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
initializeDaggerComponent();
}
@Override
public AndroidInjector<Worker> workerInjector() {
return workerDispatchingAndroidInjector;
}
private void initializeDaggerComponent() {
appComponent = DaggerAppComponent.builder().application(this).build();
appComponent.inject(this);
}
}
Step 6: Let’s define our WorkerModule class and each individual modules into it.
@Module(subcomponents = {
ProfileWorkerModule.class
})
public abstract class WorkerModule {
@Binds
@IntoMap
@WorkerKey(ProfileWorker.class) //Define your Worker class extends Worker class
abstract AndroidInjector.Factory<? extends Worker> bindProfileWorkerFactory(WorkerComponent.Builder profileWorker);
}
Step 7: Create the corresponding Module i.e., ProfileWorkerModule.class
@Subcomponent
public interface ProfileWorkerModule extends AndroidInjector<ProfileWorker> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<CustomWorkManager>{}
}
Step 8: Let's create ProfileWorker.class and inject the dependencies. As simple as that.
public class ProfileWorker extends Worker {
public static final String MODEL_OBJECT = "sync_model";
@Inject
SomeClass someClass; // Dependency is injected here
public ProfileWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
AndroidWorkerInjection.inject(this);// Injecting worker class here.
return Result.Success.success();
}
}