无法在WorkManager的Worker类中注入单例类

3
我正在使用MVVM架构,并使用Dagger2进行数据注入。我遇到的问题是,在Activity / Fragments中,@Inject正常工作,但在WorkManager的Worker类中,@Inject在运行时会出现空指针异常。我该如何解决?
以下是Worker类代码:
public class MySyncManager extends Worker {

    @Inject
    DataManager dataManager;

    @Inject
    SchedulerProvider schedulerProvider;

    @NonNull
    @Override
    public WorkerResult doWork() {

        CommonUtils.Log("usm_work_manager_1", "Work is Started.");
         if(dataManager==null) 
        CommonUtils.Log("usm_work_manager", "Injector is NULL");

    }
    }

方法:

    private void startTestSyncRequest() {
        Constraints myConstraints = new Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .build();
        OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MySyncManager.class)
                .setConstraints(myConstraints)
                .setInitialDelay(1, TimeUnit.SECONDS)  // wait for n seconds before starting service
                .build();

        WorkManager.getInstance()
                .beginUniqueWork(Tags.TEST_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
                .enqueue();

}

1
你在哪里调用 myComponent.inject(mySyncManager)?请包含注入工作者的代码。 - David Medenjak
@DavidMedenjak,我没有注入WorkManager,只是调用上述方法来启动Worker,因为它具有一些变量规则,可能会因不同的请求而异。 - Usman Rana
如果您不注入字段,它们将为“null”,因此您必须在使用之前在某个地方手动注入它。 - David Medenjak
但是我试图在Worker中注入的模型是添加在AppModule中的,在其他地方,比如activity或者fragments中都可以正常工作。对我来说,这似乎是线程特定的问题,但我不确定。 - Usman Rana
3个回答

5
要在工作类中注入字段,首先需要将您的工作类注入AppComponent中:
 fun inject(syncItemWorker: SyncItemWorker)

在worker的doWork()函数内部,您需要调用inject函数:

 if(applicationContext is MyApp){
        var daggerAppComponent= DaggerAppComponent.builder().application(applicationContext as MyApp).build()
        daggerAppComponent.inject(this)
    }

请参见:http://prntscr.com/jp7ru6。Dagger目前还不支持在Worker中进行注入。 - Usman Rana
是的,这就是为什么我要用Android Injector这种方式来实现,你可以直接注入Android框架组件,如(服务、片段、活动)。 - Shashank Srivastava
当添加以下代码行时出现错误:@Inject DataManager dataManager; - Usman Rana
@UsmanRana 你是在AppComponent中写这行代码吗?fun inject(syncItemWorker: SyncItemWorker) - Shashank Srivastava
是的,在doWork方法中,inject(this)也可以正常工作。但是当我在我的helper类上添加@Inject时,会出现编译时问题。 - Usman Rana

0

他们仍然没有对WorkManager提供内部支持。它可能会在一个新的构件(dagger-android-work)中,同时支持@ContributesAndroidInjector

但是我们可以自己创建一切来完成它。请按照以下代码操作。

AppComponent.java

    @Singleton
    @Component(modules = {//rest of your modules,
    AndroidWorkerInjectionModule.class,
    WorkerModule.class})
   public interface AppComponent {

@Component.Builder
interface Builder {

    @BindsInstance
    Builder application(Application application);

    AppComponent build();
}

void inject(App npp);

DataManager getDataManager();
}

AndroidWorkerInjectionModule.java

@Module
public abstract class AndroidWorkerInjectionModule {

@Multibinds
abstract Map<Class<? extends Worker>, AndroidInjector.Factory<? extends 
 Worker>>
workerInjectorFactories();
 }

WorkerModule.class

@Module(subcomponents = {
    WorkerComponent.class
     })
  public abstract class WorkerModule {
  @Binds
  @IntoMap
  @WorkerKey(CustomWorkManager.class)
  abstract AndroidInjector.Factory<? extends Worker> 
  bindProfileWorkerFactory(WorkerComponent.Builder profileWorker);
    }

WorkerComponent.class

@Subcomponent
public interface WorkerComponent extends AndroidInjector<CustomWorkManager> {
   //Here, CustomWorkManager is the class that extends Worker of WorkManager.You write your own class
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<CustomWorkManager>{}

}

HasWorkerInjector.class

public interface HasWorkerInjector {
AndroidInjector<Worker> workerInjector();
  }

AndroidWorkerInjection.class

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);
  }
}

WorkerKey.class

@MapKey
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface WorkerKey {
Class<? extends Worker> value();
  }

现在你可以在CustomWorkManager中注入所有的依赖项。愉快编码!


-1

不建议使用字段注入,考虑使用构造函数注入。这里有一个很好的构造函数注入示例,请查看blog。基本上你可以像这样进行注入:

@AssistedInject
public PrePopulateDataWorker(@Assisted @NonNull Context context, @Assisted @NonNull WorkerParameters workerParams, DataManager dataManager) {
    super(context, workerParams);
    this.dataManager = dataManager;
}

@AssistedInject.Factory
public interface Factory extends CustomWorkerFactory {}

这里注入了DataManger的实例。这里是Java的实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接