Dagger 2 范围和子组件

Dagger 2 scope and subcomponents

我正在尝试使用 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 class 中创建了我的组件实例,就像这样

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);

一切正常。

添加每个方法以及模块 class 被注释为 @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 范围的问题。

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

  1. 当您使用 @Singleton 注释时,匕首正在某个静态池中创建对象,该对象将存在于整个应用程序生命周期中,并在 JVM 进程(dalvik VM、ART)实例运行时被销毁被摧毁。

  2. 当你使用任何其他注解时,只是为了让开发人员更好地维护代码,@PerActivity@PerFragment只是自定义注解而已。如果您将 @PerFragment 组件放在应用程序 class 中,它会与应用程序一起存在。我对吗 ?

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

对于上述问题的任何帮助,我将不胜感激。

更新

谢谢 David Medenjak 的精彩回答,我对 Dagger2 有了更好的理解。

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

 void inject(BaseActivity baseActivity);

 void inject(MainAppActivity mainAppActivity);

现在一切正常,我喜欢Dagger2和分离架构。

有点激进,但为了简化事情: 所有作用域注解只不过是语法糖——包括@Singleton.

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

[...] dagger is creating object in some static pool that will exists during whole application lifecycle

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

[...]you place @PerFragment component in Application class it will live as long as Application lives.

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

if dagger finds @Singleton annotation it will add static reference to component when it is created first time and in case of any other annotation it won't hold reference to component.

同样,不。没有什么是静态的。普通的旧 java 对象。您可以拥有多个 @Singleton 组件和它们自己的对象,但您可能不应该这样做(尽管这使仪器测试成为可能/简单 — 只需交换组件即可。)


您提到的错误

SpiceManager cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.

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