Конфликт Кинжала

Репозиторий: 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 с полным доступом к вашим внедренным объектам.
Другие вопросы по тегам