Кинжал не может найти инъективные элементы на модуле
Я использую Dagger для инъекции зависимостей в проекте Android и могу скомпилировать и построить приложение отлично. График объекта выглядит корректным и работает, но когда я добавляю кинг-компилятор как зависимость, чтобы получить ошибки во время компиляции, он сообщает о некоторых странных ошибках:
[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
Ошибка Отто выглядит так, как Эрик Берк упоминает в своей презентации 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);
}
});
}
}
}
...
@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;
}
}
...
/**
* Module that includes all of the app modules. Used by Dagger
* for compile time validation of injections and modules.
*/
@Module(
includes = {
MGoBlogAPIModule.class,
OttoModule.class,
TaskQueueModule.class
}
)
public class MGoBlogAppModule {
}
Ответы
Ответ 1
Полный анализ графиков кинжалов работает с полным модулем. т.е. @Module (complete = true), который является значением по умолчанию. Поскольку это по умолчанию, кинжал, по умолчанию, предполагает, что все привязки доступны из этого модуля или тех модулей, которые он включает явно.
В этом случае вы предоставили два модуля, которые, по вашему мнению, полны, но у Dagger нет возможности связать их вместе во время компиляции без дополнительного сигнала. Короче говоря, без того, чтобы OttoModule знал о TaskQueueModule, компилятор попытается проанализировать OttoModule для заявленной полноты и потерпеть неудачу, поскольку теперь он не связан с TaskQueueModule.
Измените аннотацию OttoModule как таковой:
@Module(
includes = TaskQueueModule.class,
entryPoints = {
MGoBlogActivity.class,
NodeFragment.class,
NodeActivity.class,
NodeCommentFragment.class,
NodeIndexTaskService.class,
NodeTaskService.class
}
)
а затем Кинжал будет знать, что для того, чтобы OttoModule был полным, он включает в себя другой модуль как часть его полного определения.
Примечание: компилятор dagger не может обнаружить, что TaskQueueModule существует в пути класса и просто "знает", что разработчик предполагал, что он будет использоваться с OttoModule без этого дополнительного сигнала. Например, у вас может быть несколько модулей, которые определяют очереди задач и какие из них будут выбраны? Объявление должно быть явным.