匕首 2 范围和子组件

我试图使用我捕获的一般想法使我的应用程序更好,代码更易于维护,但仍然无法弄清楚如何将范围注入到我的项目中(听起来很有趣)。我创建了组件,它在我的项目中完美地工作。这是我的代码。Dagger2Dagger2ApplicationComonent

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

一切都很完美。

要添加每个方法以及模块类,请用范围注释,所有与@SingletonApplicationComponent

现在我想使依赖关系更好,我已经看到了很多带有自定义范围的示例,例如, 。我有很多问题,但稍后会这样。@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]

我不知道哪里有问题,我错过了什么。我关于匕首2中示波器的问题。

除了被匕首2忽略了之外的一切,我说的对吗?我不明白如何管理组件的寿命?我只有一个想法@Singleton

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

  2. 当你使用任何其他注释只是为了你作为开发人员更好地维护代码时,只是自定义注释仅此而已。如果您将组件放在应用程序类中,它将与应用程序一样长。我说的对吗?@PerActivity@PerFragment@PerFragment

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

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

更新

感谢您的精彩回答,我对.David MedenjakDagger2

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

 void inject(BaseActivity baseActivity);

 void inject(MainAppActivity mainAppActivity);

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


答案 1

有点激进,但要简化一些事情:所有范围注释都只是语法上的糖 - 包括@Singleton

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

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

不。匕首不会做任何静态的事情。您有组件对象。这些组件保存由模块创建的对象。如果组件中的某个对象具有该组件的作用域,则只会在该确切组件中创建一次。如果决定创建 2 个对象,则每个带注释的对象将有 2 个对象,每个对象都在其组件内。这就是您应该保留对组件的引用的原因。因此,我见过或使用过的大多数实现都将它们保留在.如果这样做,您可以像单例一使用它 - 它仍然只是一个POJO。AppComponent@SingletonAppComponentApplication

[...]您将@PerFragment组件放在应用程序类中,它将与应用程序一样长。

是的。正如上面的段落已经涵盖的那样,它只是一个对象。保留引用,保留对象。扔掉它或创建一个新对象,你就有了新对象(在此组件/范围内定义)。尽管除了分别在活动或片段中之外,您不应该将活动或片段范围的组件保留在任何位置,因为将它们保留在您的应用程序组件中很可能会导致内存泄漏。(如果没有,您可能不需要活动或片段范围。

如果匕首找到注释,它将在第一次创建组件时向组件添加静态引用,并且在任何其他注释的情况下,它不会保留对组件的引用。@Singleton

同样,没有。没有静态。普通的旧 java 对象。您可以拥有具有自己对象的多个组件,但您可能不应该(尽管这使检测测试成为可能/容易 - 只需交换组件即可。@Singleton


您提到的错误

如果没有@Inject构造函数或@Provides或@Produces注释的方法,则无法提供 SpiceManager。

这意味着您尝试注入对象的组件找不到任何方法来生成或提供 .确保从您的AppComponent或其他位置提供它,不缺少任何注释等。SpiceManager


答案 2