Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/184.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Dagger2:无法在WorkManager中注入依赖项_Android_Dagger 2_Android Workmanager - Fatal编程技术网

Android Dagger2:无法在WorkManager中注入依赖项

Android Dagger2:无法在WorkManager中注入依赖项,android,dagger-2,android-workmanager,Android,Dagger 2,Android Workmanager,所以从我读到的,Dagger还不支持InjectinWorker。但正如人们所建议的,还有一些变通办法。我在网上尝试了很多方法,但都不适合我 当我不尝试向Worker类中注入任何内容时,代码工作正常,只是我不能做我想做的事情,因为我需要访问一些DAO和服务。如果我在这些依赖项上使用@Inject,则依赖项要么为null,要么worker从未启动,即调试器甚至没有进入worker类 例如,我试着这样做: @Component(modules = {Module.class}) public int

所以从我读到的,Dagger还不支持InjectinWorker。但正如人们所建议的,还有一些变通办法。我在网上尝试了很多方法,但都不适合我

当我不尝试向Worker类中注入任何内容时,代码工作正常,只是我不能做我想做的事情,因为我需要访问一些DAO和服务。如果我在这些依赖项上使用@Inject,则依赖项要么为null,要么worker从未启动,即调试器甚至没有进入worker类

例如,我试着这样做:

@Component(modules = {Module.class})
public interface Component{

    void inject(MyWorker myWorker);
}

@Module
public class Module{

    @Provides
    public MyRepository getMyRepo(){
        return new myRepository();
    }

}
还有我的工人

@Inject
MyRepository myRepo;

public MyWorker() {
    DaggerAppComponent.builder().build().inject(this);
}
但这样的话,死刑永远不会落到工人手里。如果删除构造函数,myRepo依赖项将保持为null


我试过做很多其他的事情,但都没有成功。有没有办法做到这一点?谢谢

在WorkManager
alpha09
中,有一个新选项,您可以使用该选项以您想要的方式初始化
工作人员

  • 使用新的
    Worker
    构造函数,该构造函数接受
    ApplicationContext
    WorkerParams
  • 通过
    Configuration
    注册
    WorkerFactory
    的实现
  • 创建
    配置
    并注册新创建的
    WorkerFactory
  • 使用此配置初始化
    WorkManager
    (同时删除代表您初始化
    WorkManager
    ContentProvider
您需要执行以下操作:

public DaggerWorkerFactory implements WorkerFactory {
  @Nullable Worker createWorker(
  @NonNull Context appContext,
  @NonNull String workerClassName,
  @NonNull WorkerParameters workerParameters) {

  try {
      Class<? extends Worker> workerKlass = Class.forName(workerClassName).asSubclass(Worker.class);
      Constructor<? extends Worker> constructor = 
      workerKlass.getDeclaredConstructor(Context.class, WorkerParameters.class);

      // This assumes that you are not using the no argument constructor 
      // and using the variant of the constructor that takes in an ApplicationContext
      // and WorkerParameters. Use the new constructor to @Inject dependencies.
      Worker instance = constructor.newInstance(appContext,workerParameters);
      return instance;
    } catch (Throwable exeption) {
      Log.e("DaggerWorkerFactory", "Could not instantiate " + workerClassName, e);
      // exception handling
      return null;
    }
  }
}

// Create a configuration
Configuration configuration = new Configuration.Builder()
  .setWorkerFactory(new DaggerWorkerFactory())
  .build();

// Initialize WorkManager
WorkManager.initialize(context, configuration);
公共DaggerWorkerFactory实现WorkerFactory{ @可为空的工作者createWorker( @非空上下文appContext, @非空字符串workerClassName, @非空WorkerParameters(WorkerParameters){ 试一试{ Class我用来解决这个问题

类似的方法用于注入
ViewModel
对象(描述得很好)。与视图模型案例的重要区别在于
Context
WorkerParameters
参数在
Worker
构造函数中的存在。要向Worker构造函数提供这些参数,应使用中间匕首组件

  • @Inject
    注释
    工作者的构造函数,并提供所需的依赖项作为构造函数参数

    class HardWorker @Inject constructor(context: Context,
                                         workerParams: WorkerParameters,
                                         private val someDependency: SomeDependency)
        : Worker(context, workerParams) {
    
        override fun doWork(): Result {
            // do some work with use of someDependency
            return Result.SUCCESS
        }
    }
    
  • 创建自定义注释,指定辅助多重绑定映射项的键

    @MustBeDocumented
    @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
    @Retention(AnnotationRetention.RUNTIME)
    @MapKey
    annotation class WorkerKey(val value: KClass<out Worker>)
    
  • 定义中间组件及其生成器。该组件必须具有从依赖关系图获取辅助对象映射的方法,并在其模块中包含辅助对象绑定模块。此外,该组件必须声明为其父组件的子组件,并且父组件必须具有获取子组件生成器的方法

    typealias WorkerMap = MutableMap<Class<out Worker>, Provider<Worker>>
    
    @Subcomponent(modules = [HardWorkerModule::class])
    interface WorkerFactoryComponent {
    
        fun workers(): WorkerMap
    
        @Subcomponent.Builder
        interface Builder {
            @BindsInstance
            fun setParameters(params: WorkerParameters): Builder
            @BindsInstance
            fun setContext(context: Context): Builder
            fun build(): WorkerFactoryComponent
        }
    }
    
    // parent component
    @ParentComponentScope
    @Component(modules = [
                //, ...
            ])
    interface ParentComponent {
    
        // ...
    
        fun workerFactoryComponent(): WorkerFactoryComponent.Builder
    }
    
  • 使用自定义worker factory手动初始化
    WorkManager
    (每个进程只能执行一次)。不要忘记在清单中禁用自动初始化

  • 舱单:

        <provider
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:authorities="${applicationId}.workmanager-init"
            android:exported="false"
            tools:node="remove" />
    
  • 使用工人

    val request = OneTimeWorkRequest.Builder(workerClass).build(HardWorker::class.java)
    WorkManager.getInstance().enqueue(request)
    
  • 有关
    WorkManager
    功能的更多信息,请观看本节。

    概述 您需要查看,从
    1.0.0-alpha09
    开始提供

    以前的解决方法依赖于能够使用默认的0-arg构造函数创建
    Worker
    ,但从
    1.0.0-alpha10
    开始,这不再是一个选项

    例子 假设您有一个名为
    DataClearingWorker
    Worker
    子类,这个类需要从匕首图中得到一个
    Foo

    class DataClearingWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    
        lateinit var foo: Foo
    
        override fun doWork(): Result {
            foo.doStuff()
            return Result.SUCCESS
        }
    }
    
    现在,您不能直接实例化这些
    DataClearingWorker
    实例中的一个。因此,您需要定义一个
    WorkerFactory
    子类,该子类可以为您创建一个实例;不仅要创建一个,还要设置
    Foo
    字段

    class DaggerWorkerFactory(private val foo: Foo) : WorkerFactory() {
    
        override fun createWorker(appContext: Context, workerClassName: String, workerParameters: WorkerParameters): ListenableWorker? {
    
            val workerKlass = Class.forName(workerClassName).asSubclass(Worker::class.java)
            val constructor = workerKlass.getDeclaredConstructor(Context::class.java, WorkerParameters::class.java)
            val instance = constructor.newInstance(appContext, workerParameters)
    
            when (instance) {
                is DataClearingWorker -> {
                    instance.foo = foo
                }
                // optionally, handle other workers               
            }
    
            return instance
        }
    }
    
    最后,您需要创建一个
    DaggerWorkerFactory
    ,该工厂可以访问
    Foo
    。您可以使用普通的Dagger方法来完成此操作

    @Provides
    @Singleton
    fun workerFactory(foo: Foo): WorkerFactory {
        return DaggerWorkerFactory(foo)
    }
    
    禁用默认WorkManager初始化 您还需要禁用默认的
    WorkManager
    初始化(自动发生)并手动初始化

    AndroidManifest.xml
    中,可以如下方式禁用它:

     <provider
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:authorities="com.your.app.package.workmanager-init"
            android:enabled="false"
            android:exported="false"
            tools:replace="android:authorities" />
    

    2020/06更新

    随着时间的推移,事情变得容易多了

    有了剑柄,你所要做的就是

  • 向应用程序类添加注释
    @HiltAndroidApp
  • 在应用程序类字段中注入开箱即用
    HiltWorkerFactory
  • 执行接口
    配置。提供程序
    并在步骤2中返回注入的工作工厂
  • 现在,将Worker构造函数上的注释从
    @Inject
    更改为
    @WorkerInject

    class ExampleWorker @WorkerInject constructor(
        @Assisted appContext: Context,
        @Assisted workerParams: WorkerParameters,
        someDependency: SomeDependency // your own dependency
    ) : Worker(appContext, workerParams) { ... }
    
    就这样

    (另外,不要忘记禁用默认工作管理器初始化功能)

    ===========

    旧解决方案

    从版本1.0.0-beta01开始,这里是使用WorkerFactory实现匕首注射

    这个概念来自本文:我只是一步一步地发布我自己的实现(在Kotlin

    ===========

    此实施试图实现的目标是:

    每次要向工作程序添加依赖项时,都将该依赖项放入相关的工作程序类中

    ===========

    1.为所有工人的工厂添加一个界面

    IWorkerFactory.kt

    interface IWorkerFactory<T : ListenableWorker> {
        fun create(params: WorkerParameters): T
    }
    
    class HelloWorker(
        context: Context,
        params: WorkerParameters,
        private val apiService: ApiService // our dependency
    ): Worker(context, params) {
        override fun doWork(): Result {
            Log.d("HelloWorker", "doWork - fetchSomething")
            return apiService.fetchSomething() // using Retrofit + RxJava
                .map { Result.success() }
                .onErrorReturnItem(Result.failure())
                .blockingGet()
        }
    
        class Factory @Inject constructor(
            private val context: Provider<Context>, // provide from AppModule
            private val apiService: Provider<ApiService> // provide from NetworkModule
        ) : IWorkerFactory<HelloWorker> {
            override fun create(params: WorkerParameters): HelloWorker {
                return HelloWorker(context.get(), params, apiService.get())
            }
        }
    }
    
    @MapKey
    @Target(AnnotationTarget.FUNCTION)
    @Retention(AnnotationRetention.RUNTIME)
    annotation class WorkerKey(val value: KClass<out ListenableWorker>)
    
    @Module
    interface WorkerModule {
        @Binds
        @IntoMap
        @WorkerKey(HelloWorker::class)
        fun bindHelloWorker(factory: HelloWorker.Factory): IWorkerFactory<out ListenableWorker>
        // every time you add a worker, add a binding here
    }
    
    @Singleton
    @Component(modules = [
        AndroidSupportInjectionModule::class,
        NetworkModule::class, // provides ApiService
        AppModule::class, // provides context of application
        WorkerModule::class // <- add WorkerModule here
    ])
    interface AppComponent: AndroidInjector<App> {
        @Component.Builder
        abstract class Builder: AndroidInjector.Builder<App>()
    }
    
    class DaggerAwareWorkerFactory @Inject constructor(
        private val workerFactoryMap: Map<Class<out ListenableWorker>, @JvmSuppressWildcards Provider<IWorkerFactory<out ListenableWorker>>>
    ) : WorkerFactory() {
        override fun createWorker(
            appContext: Context,
            workerClassName: String,
            workerParameters: WorkerParameters
        ): ListenableWorker? {
            val entry = workerFactoryMap.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) }
            val factory = entry?.value
                ?: throw IllegalArgumentException("could not find worker: $workerClassName")
            return factory.get().create(workerParameters)
        }
    }
    
    class App: DaggerApplication() {
        override fun onCreate() {
            super.onCreate()
            configureWorkManager()
        }
    
        override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
            return DaggerAppComponent.builder().create(this)
        }
    
        @Inject lateinit var daggerAwareWorkerFactory: DaggerAwareWorkerFactory
    
        private fun configureWorkManager() {
            val config = Configuration.Builder()
                .setWorkerFactory(daggerAwareWorkerFactory)
                .build()
            WorkManager.initialize(this, config)
        }
    }
    
    界面IWorkerFactory{ 乐趣创建(参数:WorkerParameters):T }
    2.添加一个简单的工人类,其中包含一个工厂,该工厂实现了IWorkerFactory,并且还包含此工人的依赖项

    HelloWorker.kt

    interface IWorkerFactory<T : ListenableWorker> {
        fun create(params: WorkerParameters): T
    }
    
    class HelloWorker(
        context: Context,
        params: WorkerParameters,
        private val apiService: ApiService // our dependency
    ): Worker(context, params) {
        override fun doWork(): Result {
            Log.d("HelloWorker", "doWork - fetchSomething")
            return apiService.fetchSomething() // using Retrofit + RxJava
                .map { Result.success() }
                .onErrorReturnItem(Result.failure())
                .blockingGet()
        }
    
        class Factory @Inject constructor(
            private val context: Provider<Context>, // provide from AppModule
            private val apiService: Provider<ApiService> // provide from NetworkModule
        ) : IWorkerFactory<HelloWorker> {
            override fun create(params: WorkerParameters): HelloWorker {
                return HelloWorker(context.get(), params, apiService.get())
            }
        }
    }
    
    @MapKey
    @Target(AnnotationTarget.FUNCTION)
    @Retention(AnnotationRetention.RUNTIME)
    annotation class WorkerKey(val value: KClass<out ListenableWorker>)
    
    @Module
    interface WorkerModule {
        @Binds
        @IntoMap
        @WorkerKey(HelloWorker::class)
        fun bindHelloWorker(factory: HelloWorker.Factory): IWorkerFactory<out ListenableWorker>
        // every time you add a worker, add a binding here
    }
    
    @Singleton
    @Component(modules = [
        AndroidSupportInjectionModule::class,
        NetworkModule::class, // provides ApiService
        AppModule::class, // provides context of application
        WorkerModule::class // <- add WorkerModule here
    ])
    interface AppComponent: AndroidInjector<App> {
        @Component.Builder
        abstract class Builder: AndroidInjector.Builder<App>()
    }
    
    class DaggerAwareWorkerFactory @Inject constructor(
        private val workerFactoryMap: Map<Class<out ListenableWorker>, @JvmSuppressWildcards Provider<IWorkerFactory<out ListenableWorker>>>
    ) : WorkerFactory() {
        override fun createWorker(
            appContext: Context,
            workerClassName: String,
            workerParameters: WorkerParameters
        ): ListenableWorker? {
            val entry = workerFactoryMap.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) }
            val factory = entry?.value
                ?: throw IllegalArgumentException("could not find worker: $workerClassName")
            return factory.get().create(workerParameters)
        }
    }
    
    class App: DaggerApplication() {
        override fun onCreate() {
            super.onCreate()
            configureWorkManager()
        }
    
        override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
            return DaggerAppComponent.builder().create(this)
        }
    
        @Inject lateinit var daggerAwareWorkerFactory: DaggerAwareWorkerFactory
    
        private fun configureWorkManager() {
            val config = Configuration.Builder()
                .setWorkerFactory(daggerAwareWorkerFactory)
                .build()
            WorkManager.initialize(this, config)
        }
    }
    
    类HelloWorker(
    上下文:上下文,
    参数:WorkerParameters,
    private val apiService:apiService//我们的依赖关系
    ):工人(