Dagger在模块上找不到注射成员

Sea*_*eil 10 android dependency-injection dagger

我在Android项目中使用Dagger进行依赖注入,并且可以编译和构建应用程序.对象图看起来是正确和有效的,但是当我添加dagger-compiler作为依赖以在编译时获取错误时,它会报告一些奇怪的错误:

[ERROR] error: No binding for com.squareup.tape.TaskQueue<com.atami \
    .mgodroid.io.NodeIndexTask> required by com.atami \
    .mgodroid.ui.NodeIndexListFragment for com.atami.mgodroid \
    .modules.OttoModule
[ERROR] error: No binding for com.squareup.tape.TaskQueue<com.atami \
    .mgodroid.io.NodeTask> required by com.atami \
    .mgodroid.ui.NodeFragment for com.atami.mgodroid.modules.OttoModule
[ERROR] error: No injectable members on com.squareup.otto.Bus. Do you want 
     to add an injectable constructor? required by com.atami. \
     mgodroid.io.NodeIndexTaskService for 
     com.atami.mgodroid.modules.TaskQueueModule
Run Code Online (Sandbox Code Playgroud)

Otto错误看起来像Eric Burke在他的Android App Anatomy演示文稿中提到的没有@Provides注释,但正如你在下面我看到的那样.

我的Otto和TaskQueue模块如下:

@Module(
        entryPoints = {
                MGoBlogActivity.class,
                NodeIndexListFragment.class,
                NodeFragment.class,
                NodeActivity.class,
                NodeCommentFragment.class,
                NodeIndexTaskService.class,
                NodeTaskService.class
        }
)
public class OttoModule {

    @Provides
    @Singleton
    Bus provideBus() {
        return new AsyncBus();
    }

    /**
     * Otto EventBus that posts all events on the Android main thread
     */
    private class AsyncBus extends Bus {
        private final Handler mainThread = new Handler(Looper.getMainLooper());

        @Override
        public void post(final Object event) {
            mainThread.post(new Runnable() {
                @Override
                public void run() {
                    AsyncBus.super.post(event);
                }
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

...

@Module(
    entryPoints = {
        NodeIndexListFragment.class,
        NodeFragment.class,
        NodeIndexTaskService.class,
        NodeTaskService.class
    }
)
public class TaskQueueModule {

    private final Context appContext;

    public TaskQueueModule(Context appContext) {
        this.appContext = appContext;
    }

    public static class IOTaskInjector<T extends Task> 
        implements TaskInjector<T> {

        Context context;

        /**
         * Injects Dagger dependencies into Tasks added to TaskQueues
         *
         * @param context the application Context
         */
        public IOTaskInjector(Context context) {
            this.context = context;
        }

        @Override
        public void injectMembers(T task) {
            ((MGoBlogApplication) context.getApplicationContext())
                .objectGraph().inject(task);
        }
    }

    public static class ServiceStarter<T extends Task> 
        implements ObjectQueue.Listener<T> {

        Context context;
        Class<? extends Service> service;

        /**
         * Starts the provided service when a Task is added to the queue
         *
         * @param context the application Context
         * @param service the Service to start
         */
        public ServiceStarter(Context context, 
                              Class<? extends Service> service) {
            this.context = context;
            this.service = service;
        }

        @Override
        public void onAdd(ObjectQueue<T> queue, T entry) {
            context.startService(new Intent(context, service));

        }

        @Override
        public void onRemove(ObjectQueue<T> queue) {
        }
    }


    @Provides
    @Singleton
    TaskQueue<NodeIndexTask> provideNodeIndexTaskQueue() {
        ObjectQueue<NodeIndexTask> delegate = 
            new InMemoryObjectQueue<NodeIndexTask>();
        TaskQueue<NodeIndexTask> queue = new TaskQueue<NodeIndexTask>(
            delegate, new IOTaskInjector<NodeIndexTask>(appContext));
        queue.setListener(new ServiceStarter<NodeIndexTask>(
            appContext, NodeIndexTaskService.class));
        return queue;
    }

    @Provides
    @Singleton
    TaskQueue<NodeTask> provideNodeTaskQueue() {
        ObjectQueue<NodeTask> delegate = 
            new InMemoryObjectQueue<NodeTask>();
        TaskQueue<NodeTask> queue = new TaskQueue<NodeTask>(
            delegate, new IOTaskInjector<NodeTask>(appContext));
        queue.setListener(new ServiceStarter<NodeTask>(
            appContext, NodeTaskService.class));
        return queue;
    }
}
Run Code Online (Sandbox Code Playgroud)

...

/**
 * Module that includes all of the app's modules. Used by Dagger
 * for compile time validation of injections and modules.
 */
@Module(
        includes = {
                MGoBlogAPIModule.class,
                OttoModule.class,
                TaskQueueModule.class
        }
)
public class MGoBlogAppModule {
}
Run Code Online (Sandbox Code Playgroud)

Chr*_*ber 19

Dagger的完整图表分析工作在一个完整的模块中.即@Module(complete = true),这是默认值.因为它是默认值,所以默认情况下,dagger会假设所有绑定都可以从该模块或它明确包含的那些模块中获得.

在这种情况下,您已经提供了两个声称已完成的模块,但Dagger无法在编译时将这些模块绑定在一起,而无需额外的信号.简而言之,如果没有OttoModule知道TaskQueueModule,编译器将尝试分析OttoModule声称的完整性,并且失败,因为它现在不关于TaskQueueModule.

修改OttoModule的注释:

@Module(
  includes = TaskQueueModule.class,
  entryPoints = {
    MGoBlogActivity.class,
    NodeFragment.class,
    NodeActivity.class,
    NodeCommentFragment.class,
    NodeIndexTaskService.class,
    NodeTaskService.class
  }
)
Run Code Online (Sandbox Code Playgroud)

然后Dagger会知道,要使OttoModule完整,它将其他模块作为其完整定义的一部分.

注意: dagger-compiler无法检测到类路径上存在TaskQueueModule,只是"知道"开发人员希望它与OttoModule一起使用而没有附加信号.例如,您可能有几个模块定义任务队列,它会选择哪一个?声明必须明确.

  • 如果可以通过本身的@Provides方法,显式"包含"模块中的@Provides方法,或者可发现的可注入类(具有@Inject字段的类)找到满足其入口点需求的所有绑定,则模块完成或构造函数). (2认同)