Dagger 2.11 ContributesAndroidInjector Singleton依赖注入失败

时间:2017-07-20 22:56:02

标签: dagger-2 dagger

我正在从Dagger 2.11中探索新的dagger.android。我希望不必创建像@PerActivity这样的自定义范围注释。到目前为止,我能够做到以下几点:

1)定义应用程序范围单例并将它们注入活动。

2)使用@ContributesAndroidInjector

定义活动范围非单身依赖关系并将其注入活动

我无法弄清楚如何使用它的应用程序范围Singleton和Activity范围非单例。

在下面的示例中,我希望我的活动范围MyActivityDependencyAMyActivityDependencyB可以访问单身MyActivityService

以下设置导致:

  

错误:(24,3)错误:com.example.di.BuildersModule_BindMyActivity.MyActivitySubcomponent       (unscoped)可能不引用范围绑定:       @Singleton @Provides com.example.MyActivityService       com.example.MyActivitySingletonsModule.provideMyActivityService()

这是我的设置。注意,我定义了单独的MyActivitySingletonsModuleMyActivityModule,因为我无法在同一个模块文件中混合使用Singleton和非Singleton依赖项。

@Module
public abstract class BuildersModule {
    @ContributesAndroidInjector(modules = {MyActivitySingletonsModule.class, MyActivityModule.class})
    abstract MyActivity bindMyActivity();
    }
}

@Module
public abstract class MyActivityModule {
    @Provides
    MyActivityDependencyA provideMyActivityDependencyA(MyActivityService myActivityService){
       return new MyActivityDependencyA(myActivityService);
    }
    @Provides
    MyActivityDependencyB provideMyActivityDependencyB(MyActivityService myActivityService) {
        return new MyActivityDependencyB(myActivityService);
    }
}

@Module
public abstract class MyActivitySingletonsModule {
    @Singleton
    @Provides
    MyActivityService provideMyActivityService() {
        return new MyActivityService();
    }
}

@Singleton
 @Component(modules = {
    AndroidSupportInjectionModule.class,
    AppModule.class,
    BuildersModule.class})

public interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(App application);
        AppComponent build();
    }
    void inject(App app);
}

在没有定义自定义范围注释的情况下,甚至可以做我想做的事情吗?

提前致谢!

2 个答案:

答案 0 :(得分:9)

为什么要避免自定义范围? Dagger 2.10 +中引入的新 dagger.android 依赖注入框架仍然需要自定义范围。

  

"我的理解是sysctl -w kern.maxfiles=20480 sysctl -w kern.maxfilesperproc=22480 ulimit -S -n 2048 消除了对自定义注释的需求,并且我能够通过使用活动范围中定义的非单例来证明它而没有任何问题。"

@ContributesAndroidInjector(在v2.11中提供)不会消除对自定义作用域的需要。它只是替换了声明@ContributesAndroidInjector类的需要,这些类没有使用@Subcomponent来注入组件在运行时所需的依赖项。请查看official dagger.android user guide about @ContributesAndroidInjector;

中的以下代码段
  

" Pro-tip:如果您的子组件及其构建器没有其他方法或超类型,而不是步骤#2中提到的方法或超类型,则可以使用@ContributesAndroidInjector为您生成它们。而不是第2步和第3步,添加一个返回活动的抽象模块方法,使用@ContributesAndroidInjector对其进行注释,并指定要安装到子组件中的模块。如果子组件需要范围,也可以将范围注释应用于方法。"

@Subcomponent.Builder

这里的关键是"如果子组件需要范围,也可以将范围注释应用于方法。"

请查看以下代码,了解如何将@ActivityScope @ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ }) abstract YourActivity contributeYourActivityInjector(); @Singleton@PerActivity@PerFragment自定义范围与新匕首一起使用的概述.android 注入框架。

@PerChildFragment

有关使用// Could also extend DaggerApplication instead of implementing HasActivityInjector // App.java public class App extends Application implements HasActivityInjector { @Inject AppDependency appDependency; @Inject DispatchingAndroidInjector<Activity> activityInjector; @Override public void onCreate() { super.onCreate(); DaggerAppComponent.create().inject(this); } @Override public AndroidInjector<Activity> activityInjector() { return activityInjector; } } // AppModule.java @Module(includes = AndroidInjectionModule.class) abstract class AppModule { @PerActivity @ContributesAndroidInjector(modules = MainActivityModule.class) abstract MainActivity mainActivityInjector(); } // AppComponent.java @Singleton @Component(modules = AppModule.class) interface AppComponent { void inject(App app); } // Could also extend DaggerActivity instead of implementing HasFragmentInjector // MainActivity.java public final class MainActivity extends Activity implements HasFragmentInjector { @Inject AppDependency appDependency; // same object from App @Inject ActivityDependency activityDependency; @Inject DispatchingAndroidInjector<Fragment> fragmentInjector; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { AndroidInjection.inject(this); super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); if (savedInstanceState == null) { addFragment(R.id.fragment_container, new MainFragment()); } } @Override public final AndroidInjector<Fragment> fragmentInjector() { return fragmentInjector; } } // MainActivityModule.java @Module public abstract class MainActivityModule { @PerFragment @ContributesAndroidInjector(modules = MainFragmentModule.class) abstract MainFragment mainFragmentInjector(); } // Could also extend DaggerFragment instead of implementing HasFragmentInjector // MainFragment.java public final class MainFragment extends Fragment implements HasFragmentInjector { @Inject AppDependency appDependency; // same object from App @Inject ActivityDependency activityDependency; // same object from MainActivity @Inject FragmentDependency fragmentDepency; @Inject DispatchingAndroidInjector<Fragment> childFragmentInjector; @SuppressWarnings("deprecation") @Override public void onAttach(Activity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // Perform injection here before M, L (API 22) and below because onAttach(Context) // is not yet available at L. AndroidInjection.inject(this); } super.onAttach(activity); } @Override public void onAttach(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Perform injection here for M (API 23) due to deprecation of onAttach(Activity). AndroidInjection.inject(this); } super.onAttach(context); } @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.main_fragment, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); if (savedInstanceState == null) { addChildFragment(R.id.child_fragment_container, new MainChildFragment()); } } @Override public final AndroidInjector<Fragment> fragmentInjector() { return childFragmentInjector; } } // MainFragmentModule.java @Module public abstract class MainFragmentModule { @PerChildFragment @ContributesAndroidInjector(modules = MainChildFragmentModule.class) abstract MainChildFragment mainChildFragmentInjector(); } // MainChildFragment.java public final class MainChildFragment extends Fragment { @Inject AppDependency appDependency; // same object from App @Inject ActivityDependency activityDependency; // same object from MainActivity @Inject FragmentDependency fragmentDepency; // same object from MainFragment @Inject ChildFragmentDependency childFragmentDepency; @Override public void onAttach(Context context) { AndroidInjection.inject(this); super.onAttach(context); } @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.main_child_fragment, container, false); } } // MainChildFragmentModule.java @Module public abstract class MainChildFragmentModule { } // PerActivity.java @Scope @Retention(RetentionPolicy.RUNTIME) public @interface PerActivity { } // PerFragment.java @Scope @Retention(RetentionPolicy.RUNTIME) public @interface PerFragment { } // PerChildFragment.java @Scope @Retention(RetentionPolicy.RUNTIME) public @interface PerChildFragment { } // AppDependency.java @Singleton public final class AppDependency { @Inject AppDependency() { } } // ActivityDependency.java @PerActivity public final class ActivityDependency { @Inject ActivityDependency() { } } // FragmentDependency.java @PerFragment public final class FragmentDependency { @Inject FragmentDependency() { } } // ChildFragmentDependency.java @PerChildFragment public final class ChildFragmentDependency { @Inject ChildFragmentDependency() { } } 和上述自定义范围的完整dagger.android 2.11设置指南,请阅读this article

答案 1 :(得分:2)

这里存在一些问题:首先,ActivitySingleton没有多大意义。依赖项是单例(每个应用程序,或应用程序作用域)或不是。

如果它不是单身,那么它可以是活动范围(每个活动)。这意味着它与活动一起生存和死亡,即它的生命周期与活动本身的生命周期一致,因此它将被活动的onDestroy破坏。

这并不意味着在Activity中注入的所有内容都必须是@PerActivity。你仍然可以在那里注入@Singleton个依赖项(比如每个应用程序OkHttpClient)。但是,这些@Singleton依赖项不会绑定在组成@PerActivity组件的模块集中。相反,它们将绑定在父组件的模块集中,并通过组件层次结构(依赖组件或子组件)获得。

这意味着您的ActivitySingletonsModule不正确,请参阅以下代码中的注释:

@Module
public abstract class MyActivitySingletonsModule {
    //@Singleton
    //^^ remove the annotation here if you want to use the
    //in your ActivityComponent

    //If you need this as a per-app singleton, then include 
    //this module at the AppComponent level
    @Provides
    MyActivityService provideMyActivityService() {
        return new MyActivityService();
    }
}

我不明白不愿意定义自定义范围。它们非常轻巧,可以提高可读性。以下是创建@PerActivity范围所需的单行代码。

@Scope @Retention(RetentionPolicy.RUNTIME) public @interface PerActivity {}

我怀疑范围的概念不清楚,这导致了不情愿。不可否认,它可能相当令人困惑。然而,有一些非常好的规范答案有助于澄清。我建议将这个问题作为一个开始:

Dagger2 Custom Scopes : How do custom-scopes (@ActivityScope) actually work?