Dagger 2范围和子组件

CRO*_*OSP 30 java android scope dependency-injection dagger-2

我试图让我的应用程序更好,代码更易于维护,Dagger2我抓住了一般的想法,但仍然无法弄清楚范围是如何管理Dagger2 我把dagger注入我的项目(听起来很有趣).我创建了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);
}
Run Code Online (Sandbox Code Playgroud)

我在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);
    }
Run Code Online (Sandbox Code Playgroud)

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

    MyApplication application = MyApplication.get(this);
    application.getApplicationComponent().inject(this);
Run Code Online (Sandbox Code Playgroud)

一切都很完美.

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

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

所以我创造了 ActivityComponent

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

    void inject(BaseActivity baseActivity);
}
Run Code Online (Sandbox Code Playgroud)

所有模块都是这样的

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

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

    @Provides
    @PerActivity
    Activity provideActivity() {
        return this.mActivity;
    }
}
Run Code Online (Sandbox Code Playgroud)

我有以下依赖关系 BaseActivity

// Dependencies from ApplicationComponent
    @Inject
    protected ApplicationSettingsManager mApplicationSettingsManager;
    @Inject
    protected ScheduledThreadPoolExecutor mPoolExecutor;
// Dependencies from ActivityComponent
    @Inject
    protected SpiceManager mSpiceManager;
    @Inject
    protected PermissionController mPermissionController;
Run Code Online (Sandbox Code Playgroud)

在我的onCreate()方法中,我注射如下

    MyApplication application = MyApplication.get(this);
    application.getApplicationComponent().activityComponent(new ActivityModule(this)).inject(this);
Run Code Online (Sandbox Code Playgroud)

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

   MyApplication application = MyApplication.get(this);
        application.getApplicationComponent().inject(this);
Run Code Online (Sandbox Code Playgroud)

现在我收到了一个错误

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]
Run Code Online (Sandbox Code Playgroud)

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

@SingletonDagger 2忽略了一切,我是对的吗?我不明白组件的生命是如何管理的?我只有一个想法

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

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

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

对于上述问题的任何帮助,我将非常感激.

UPDATE

谢谢你David Medenjak的回答,我对此有了更深入的了解Dagger2.

我刚刚发现了这个问题,就我现在使用单独的Activity组件而言,我忘记了两行,ApplicationComponent并改变了我的MainActivityto ActivityComponent而不是更改inejction ApplicationComponent,所以肯定它无法解决子组件的依赖关系.

 void inject(BaseActivity baseActivity);

 void inject(MainAppActivity mainAppActivity);
Run Code Online (Sandbox Code Playgroud)

现在一切都很完美,我喜欢Dagger2和分离建筑.

Dav*_*jak 61

有点激进,但为了简化事情: 所有范围注释都只是语法糖 - 包括@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或其他地方提供,不遗漏任何注释等.

  • 谢谢你的解释!我真的需要这样的答案,我读了很多关于"Dagger2"的不同文章,但是有任何关于scoped的内容. (2认同)