Dagger2:无法在WorkManager中注入依赖项 [英] Dagger2: Unable to inject dependencies in WorkManager

查看:128
本文介绍了Dagger2:无法在WorkManager中注入依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,据我所读,Dagger还不支持在Worker中插入.但是,正如人们建议的那样,有一些解决方法.我已经尝试了多种方法来遵循网上示例,但是没有一个对我有用.

当我不尝试向Worker类中注入任何内容时,代码可以正常工作,仅是因为我需要访问某些DAO和服务而无法做我想做的事情.如果我在这些依赖项上使用@Inject,则依赖项为null或工作程序从不启动,即调试器甚至都没有进入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依赖项将保持为空.

我尝试做许多其他事情,但没有任何效果.有没有办法做到这一点?谢谢!

解决方案

概述

您需要查看从1.0.0-alpha09开始可用的 WorkerFactory .

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

示例

假设您有一个名为DataClearingWorkerWorker子类,并且该类需要Dagger图中的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
    }
}

最后,您需要创建一个有权访问FooDaggerWorkerFactory.您可以使用正常匕首的方式进行此操作.

@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" />

请确保将 com.your.app.package 替换为实际应用的软件包.上方的<provider块位于内部标签中..因此,它是ActivitiesServices等的同级兄弟.

在您的Application子类中(或者,如果愿意,可以在其他位置),您可以手动初始化WorkManager.

@Inject
lateinit var workerFactory: WorkerFactory

private fun configureWorkManager() {
    val config = Configuration.Builder()
        .setWorkerFactory(workerFactory)
        .build()

    WorkManager.initialize(this, config)
}

So from what I read, Dagger doesn't have support for inject in Worker yet. But there are some workarounds as people suggest. I have tried to do it a number of ways following examples online but none of them work for me.

When I don't try to inject anything into the Worker class, the code works fine, only that I can't do what I want because I need access to some DAOs and Services. If I use @Inject on those dependencies, the dependencies are either null or the worker never starts i.e the debugger doesn't even enter the Worker class.

For eg I tried doing this:

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

    void inject(MyWorker myWorker);
}

@Module
public class Module{

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

}

And in my worker

@Inject
MyRepository myRepo;

public MyWorker() {
    DaggerAppComponent.builder().build().inject(this);
}

But then the execution never reaches the worker. If I remove the constructor, the myRepo dependency remains null.

I tried doing many other things but none work. Is there even a way to do this? Thanks!!

解决方案

Overview

You need to look at WorkerFactory, available from 1.0.0-alpha09 onwards.

Previous workarounds relied on being able to create a Worker using the default 0-arg constructor, but as of 1.0.0-alpha10 that is no longer an option.

Example

Let's say that you have a Worker subclass called DataClearingWorker, and that this class needs a Foo from your Dagger graph.

class DataClearingWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {

    lateinit var foo: Foo

    override fun doWork(): Result {
        foo.doStuff()
        return Result.SUCCESS
    }
}

Now, you can't just instantiate one of those DataClearingWorker instances directly. So you need to define a WorkerFactory subclass that can create one of them for you; and not just create one, but also set your Foo field too.

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

Finally, you need to create a DaggerWorkerFactory which has access to the Foo. You can do this in the normal Dagger way.

@Provides
@Singleton
fun workerFactory(foo: Foo): WorkerFactory {
    return DaggerWorkerFactory(foo)
}

Disabling Default WorkManager Initialization

You'll also need to disable the default WorkManager initialization (which happens automatically) and initialize it manually.

In the AndroidManifest.xml, you can disable it like this:

 <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" />

Be sure to replace com.your.app.package with your actual app's package. The <provider block above goes inside your <application tag.. so it's a sibling of your Activities, Services etc...

In your Application subclass, (or somewhere else if you prefer), you can manually initialize WorkManager.

@Inject
lateinit var workerFactory: WorkerFactory

private fun configureWorkManager() {
    val config = Configuration.Builder()
        .setWorkerFactory(workerFactory)
        .build()

    WorkManager.initialize(this, config)
}

这篇关于Dagger2:无法在WorkManager中注入依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆