【问题标题】:Dagger 2 scope and subcomponentsDagger 2 范围和子组件
【发布时间】:2016-07-22 04:02:39
【问题描述】:

我正在尝试使用 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注解时,匕首是在某个静态池中创建对象,该对象将在整个应用程序生命周期中存在,并在JVM进程(dalvik VM,ART)实例被销毁时被销毁。

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

  3. 1234563 /p>

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

更新

感谢David Medenjak 的精彩回答,我对Dagger2 有了更深入的了解。

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

 void inject(BaseActivity baseActivity);

 void inject(MainAppActivity mainAppActivity);

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

【问题讨论】:

  • 我遇到了和你一样的问题。从您更新的答案中,我仍然不确定要修复什么。您能否分享一些源代码,以便我更好地了解?

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


【解决方案1】:

有点激进,但为了简化事情: 所有 Scope 注释都不过是语法糖——包括@Singleton

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

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

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

[...]您将 @PerFragment 组件放在 Application 类中,它将与 Application 一样存在。

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

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

再次,不。没有什么静态的。普通的旧 java 对象。您可以拥有多个带有自己的对象的 @Singleton 组件,但您可能不应该(尽管这是使仪器测试成为可能/容易的原因——只需交换组件。)


你提到的错误

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

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

【讨论】:

  • 感谢您的精彩解释!我真的需要这样的答案,我阅读了很多关于 Dagger2 的不同文章,但有任何关于幕后作用域的消息。
  • 这个答案揭开了 Dagger 2 的神秘面纱,这会让它看起来很混乱。迄今为止,文档并不出色,但它一直在变得更好 - 如果每个人在开始使用 Dagger 2 时都阅读此答案,那将对他们有很大帮助。
  • 真的很棒的解释!
  • If an object in a component has the scope of the component, it will only be created once in that exact component. If you decide to create 2 AppComponent objects, you will have 2 objects of each @Singleton annotated object, each within its component超级
  • 很好的答案,超级简单的解释。完全同意@MarkKeen
猜你喜欢
  • 1970-01-01
  • 2016-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-06
  • 2015-06-17
  • 1970-01-01
相关资源
最近更新 更多