Конфликт Кинжала
Репозиторий: https://github.com/googlesamples/android-architecture
Ветка - Тодо-мвп-кинжал
Обнаружено, что TaskFragment вводится с помощью contructorinjection
Например: в TasksModule я хочу добавить еще один модуль для фрагмента задачи, как показано ниже для поля Injection в TaskFragment.
@Module
class TasksModule{
@Fragmentscoped
@contributesandroidinjector(modules = AnotherModule.class)
abstract TasksFragment tasksFragment();
}
@Module
public class AnotherModule {
@Provides
@FragmentScoped
static Calendar getCalendar() {
return Calendar.getInstance();
}
}
@activityscoped
public class TasksFragment extends DaggerFragment implements TasksContract.View {
@Inject
Calendar calendar;//Field injection
@Inject
TasksFragment(){
}
}
Деятельность:
public class TasksActivity extends DaggerAppCompatActivity {
@Inject
Lazy<TasksFragment> taskFragmentProvider;
....
}
Я получаю ошибку как:
Error:(34, 8) error: [dagger.android.AndroidInjector.inject(T)] java.util.Calendar cannot be provided without an @Provides- or @Produces-annotated method.
java.util.Calendar is injected at
com.example.android.architecture.blueprints.todoapp.tasks.TasksFragment.calendar
dagger.Lazy<com.example.android.architecture.blueprints.todoapp.tasks.TasksFragment> is injected at
com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity.taskFragmentProvider
com.example.android.architecture.blueprints.todoapp.tasks.TasksActivity is injected at
dagger.android.AndroidInjector.inject(arg0)
A binding with matching key exists in component: com.example.android.architecture.blueprints.todoapp.tasks.TasksModule_TasksFragment.TasksFragmentSubcomponent
Я что-то здесь упускаю в отношении инъекций?
1 ответ
Чтобы ответить на ваш вопрос напрямую, вы, очевидно, пытаетесь создать экземпляр TasksFragment из компонента ActivityComponent. Однако вы связали свой Календарь в области видимости @FragmentScoped внутри подкомпонента, специфичного для фрагмента, который создает для вас dagger.android. Это означает, что Календарь доступен только из вашего Фрагмента (и других объектов, к которым у вас есть доступ к Фрагменту), а не из вашей Деятельности.
Если вам нужна правильная область действия и компонент для внедрения, вы должны использовать компонент Fragment, который имеет сгенерированное имя и не имеет метода создания фрагмента: он не предназначен для такого вызова.
Простой ответ: не полагайтесь на инжектор конструктора здесь. Вы должны звонить new
на вашем фрагменте, потому что это то, что делает Android; специально для этой цели у вас должен быть открытый конструктор без параметров, и Android не будет вставлять ваш фрагмент при создании. Хотя здесь нет никаких специальных правил Даггера относительно внедрения конструктора и поля, это ограничение системы Android и ее необходимой способности воссоздавать экземпляры фрагмента для вас.
Вместо этого, расширяя DaggerFragment, вы даете Dagger команду вставить свой фрагмент в его onAttach
метод, который является правильным способом, и способ, для которого предназначен dagger.android. Если бы вы внедрили фрагмент ранее, вручную или автоматически, то эти поля @Inject будут заменены и повторно введены при присоединении фрагмента... и ваш фрагмент будет отличаться в зависимости от того, будет ли Android автоматически создавать объект для вас, или делаете ли вы это сами.
Другие заметки:
- Не важно внедрить сам ваш фрагмент с помощью @FragmentScoped, потому что Dagger будет создавать новый экземпляр вашего компонента всякий раз, когда ваш фрагмент присоединен, и если какая-либо из зависимостей вашего фрагмента внедрит TasksFragment, они получат правильный экземпляр фрагмента из-за привязки экземпляра в Subcomponent.Builder, который dagger.android генерирует для вас.
- Пожалуйста, не обращайтесь к
@Inject Lazy<TasksFragment> taskFragmentProvider
как поставщик: в отличие от генералаProvider
,Lazy
всегда будет возвращать один и тот же экземпляр, даже если объект не имеет области видимости. - Вы можете взаимодействовать со своим Фрагментом после его создания и перед его присоединением, но единственное, что вам следует ожидать, это назначить ему Пакет, содержащий аргументы экземпляра Фрагмента. Это дает Android гибкость, необходимую для создания и воссоздания объекта, и предоставляет ваш комплект для
onAttach
метод, в котором вы можете использовать эти аргументы Bundle с полным доступом к вашим внедренным объектам.