匕首范围冲突

时间:2017-11-23 16:16:08

标签: android dagger

Reprository:https://github.com/googlesamples/android-architecture

Branch - todo-mvp-dagger

发现使用contructorinjection注入TaskFragment

例如: 在TasksModule中,我想为任务片段添加另一个模块,如下面的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 个答案:

答案 0 :(得分:2)

要直接回答您的问题,您显然正在尝试从ActivityComponent中实例化您的TasksFragment。但是,您已在@ragrag.Sandped范围内将日历绑定在dagger.android为您创建的特定于片段的子组件中。这意味着Calendar只能从Fragment(以及Fragment访问的其他对象)中获取,而不能从您的Activity中获取。

如果你想要正确的范围和注入组件,你可以使用Fragment的组件,它有一个生成的名称,没有片段构造方法:它的设计不是为了调用它方式。

答案很简单:不要依赖构造函数注入。你应该在你的片段上调用new,因为这是Android的作用; you are required to have a public parameterless constructor专门用于此目的,Android不会在构建时注入您的Fragment。虽然这里没有关于构造函数注入和字段注入的任何特殊Dagger规则,但这是Android系统的约束以及为您重新创建Fragment实例的必要能力。

相反,通过扩展DaggerFragment,你是instructing Dagger to inject your Fragment in its onAttach method,这是正确的方法,以及dagger.android的设计方式。如果您要先手动或自动注入Fragment,那么当附加Fragment时,这些@Inject字段将被替换并重新注入...并且您的Fragment会有不同的行为,具体取决于Android是否自动为您创建对象,或者你是否自己这样做。

其他说明:

  • 使用@FragmentScoped注入Fragment本身并不重要,因为Dagger会在你的片段被附加时创建你的组件的新实例,并且如果你的任何Fragment的依赖项注入TasksFragment,它们将得到正确的Fragment实例,因为dagger.android为您生成的Subcomponent.Builder中绑定了实例。
  • 请不要将@Inject Lazy<TasksFragment> taskFragmentProvider称为提供者:与普通Provider不同,Lazy将始终返回相同的实例,即使该对象是无范围的。< / LI>
  • 您可以在创建Fragment之后和附加之前与Fragment进行交互,但您唯一应该做的就是assign it a Bundle包含Fragment的实例参数。这使Android具有创建和重新创建对象所需的灵活性,并将为您的Bundle提供onAttach方法,您可以使用这些Bundle参数对注入的对象具有完全访问权。