Dagger 2范围和子组件

时间:2016-04-02 09:50:19

标签: java android dependency-injection scope dagger-2

我正在尝试使用Dagger2让我的应用更好,代码更易于维护我抓住了一般的想法,但仍无法弄清楚范围是如何由Dagger2管理的 我在我的项目中注入了匕首(听起来很有趣)。 我创建了ApplicationComonent组件,它在我的项目中完美运行。 这是我的代码。

@Singleton
@Component(modules = {
        ApplicationModule.class,
        ThreadingModule.class,
        NetworkModule.class,
        DatabaseModule.class,
        ServiceModule.class,
        ParseModule.class,
        PreferencesSessionModule.class})

public interface ApplicationComponent {
    ActivityComponent activityComponent(ActivityModule activityModule);

    void inject(BaseActivity baseActivity);

    void inject(MainAppActivity mainAppActivity);

    void inject(MyApplication application);

    void inject(BaseFragment baseFragment);

    void inject(MyService service);

    void inject(RegistrationIntentService service);
}

我在MyApplication类中创建我的组件实例,就像这样

private void initializeAndInjectComponent() {
        mApplicationComponent =
                DaggerApplicationComponent
                        .builder()
                        .threadingModule(new ThreadingModule(1))
                        .applicationModule(new ApplicationModule(this))
                        .networkModule(new NetworkModule(
                                MyService.API_SERVER_BASE_URL,
                                MyService.TIMEOUT))
                        .build();
        mApplicationComponent.inject(this);
    }

我可以获取组件以便注入我的Activities

    MyApplication application = MyApplication.get(this);
    application.getApplicationComponent().inject(this);

一切都很完美。

添加每个方法以及模块类都使用@Singleton范围进行注释,所有模块都与ApplicationComponent

相关

现在我想更好地建立依赖关系,我已经看到很多自定义范围的示例,例如@PerActivity@PerFragment。我有很多问题,但稍后会这样。

所以我创建了ActivityComponent

@PerActivity
@Subcomponent(
        modules = {
                NetworkServiceModule.class,
                ActivityModule.class,
                PermissionModule.class
        })
public interface ActivityComponent {
    Activity activity();

    void inject(BaseActivity baseActivity);
}

所有模块都是这样的

@PerActivity
@Module
public class ActivityModule {
    private Activity mActivity;

    public ActivityModule(Activity activity) {
        this.mActivity = activity;
    }

    @Provides
    @PerActivity
    Activity provideActivity() {
        return this.mActivity;
    }
}

我的BaseActivity

中有以下依赖项
// Dependencies from ApplicationComponent
    @Inject
    protected ApplicationSettingsManager mApplicationSettingsManager;
    @Inject
    protected ScheduledThreadPoolExecutor mPoolExecutor;
// Dependencies from ActivityComponent
    @Inject
    protected SpiceManager mSpiceManager;
    @Inject
    protected PermissionController mPermissionController;

在我的onCreate()方法中,我注入了以下内容

    MyApplication application = MyApplication.get(this);
    application.getApplicationComponent().activityComponent(new ActivityModule(this)).inject(this);

在创建子组件ActivityComponent之前,它是

   MyApplication application = MyApplication.get(this);
        application.getApplicationComponent().inject(this);

现在我收到了错误

Error:(34, 10) error: com.octo.android.robospice.SpiceManager cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
BaseActivity.mSpiceManager
[injected field of type: com.octo.android.robospice.SpiceManager mSpiceManager]

我无法弄清楚问题在哪里,我错过了什么。 我对dagger2中的范围有疑问。

Dagger 2忽略了@Singleton以外的所有内容,我是对的吗? 我不明白组件的生命是如何管理的?我只有一个想法

  1. 当您使用@Singleton注释时,dagger会在整个应用程序生命周期中存在的某个静态池中创建对象,并且在销毁JVM进程(dalvik VM,ART)实例时将被销毁。

  2. 当您使用任何其他注释时,您只需为开发人员更好地维护代码,@PerActivity@PerFragment只是自定义注释。如果您在Application类中放置@PerFragment组件,只要应用程序存在,它就会存在。我对吗 ?

  3. 所以我理解这一点,如果dagger找到@Singleton注释,它将在第一次创建时添加对组件的静态引用,如果是任何其他注释,它将不会保留对组件的引用

  4. 我非常感谢上述问题的任何帮助。

    更新

    感谢David Medenjak获得了很好的答案,我对Dagger2有了更深入的了解。

    我刚刚发现了问题,就我现在使用单独的Activity组件而言,我忘记了ApplicationComponent中的两行并将MainActivity中的inejction更改为{{ 1}}而不是ActivityComponent,所以肯定它无法解析子组件的依赖关系。

    ApplicationComponent

    现在一切都很完美,我喜欢 void inject(BaseActivity baseActivity); void inject(MainAppActivity mainAppActivity); 和分离的架构。

1 个答案:

答案 0 :(得分:60)

有点激进,但为了简化事情: 所有范围注释都只是语法糖 - 包括@Singleton

范围主要是提供编译时间检查。循环依赖关系,或者您可能错过的事情的错误。 @Singleton就像任何其他范围一样,唯一的区别是它是一个已经存在的注释,您不必自己创建它。您可以改为使用@MySingleton

  

[...] dagger在整个应用程序生命周期中存在的某个静态池中创建对象

没有。 Dagger没有没有静态。你有组件对象。这些组件包含由模块创建的对象。如果组件中的对象具有组件的范围,则只会在中创建一个组件。如果您决定创建2个AppComponent个对象,则每个@Singleton注释对象将包含2个对象,每个对象位于其组件中。这就是为什么你应该保留对组件的引用。我见过或使用的大多数实现因此将AppComponent保留在Application内。如果你这样做,你可以使用喜欢一个单身 - 它仍然只是一个POJO。

  

[...]你将@PerFragment组件放在Application类中,只要应用程序存在,它就会存在。

是。如上段所述,它只是一个对象。保留参考,保留对象。扔掉它或创建一个新的对象(在此组件/范围内定义)。尽管分别在活动或片段之外的任何地方保留活动或片段范围组件,但应保留它们,例如在您的应用程序组件中很可能会导致内存泄漏。 (如果它没有,你可能不需要活动或片段范围。)

  

如果dagger找到@Singleton注释,它将在第一次创建时添加对组件的静态引用,如果是任何其他注释,它将不会保留对组件的引用。

再一次,没有。没什么是静止的。普通的旧java对象。您可以将多个@Singleton组件与自己的对象组合在一起,但您可能不应该这样做(尽管这使得仪器测试变得可行/简单 - 只需交换组件。)

您提到的错误

  

如果没有@Inject构造函数或@ Provide-或@ Produces-annotated方法,则无法提供SpiceManager。

这意味着您尝试注入对象的组件无法找到生成或提供SpiceManager的任何方法。确保您从AppComponent或其他地方提供,不遗漏任何注释等。