Dagger2 注入很多activities/fragments/services(可能得到很多NPE)

Dagger2 Inject a lot of activities/fragments/services (possible get a lot of NPE)

我们使用了 RoboGuice,但它已被弃用,我开始用 Dagger2 替换它。

// https://github.com/google/dagger
compile('com.google.dagger:dagger:2.7')
annotationProcessor 'com.google.dagger:dagger-compiler:2.7'
provided 'org.glassfish:javax.annotation:10.0-b28'

@Module
public class ApplicationModule {
    Application mApp;

    public ApplicationModule(@NonNull Application app) {
        Preconditions.checkNotNull(app);
        mApp = app;
    }

    @Provides
    @Singleton
    public SharedPreferences providesSharedPrefs() {
        return PreferenceManager.getDefaultSharedPreferences(mApp);
    }

    @Provides
    @Singleton
    public DateHelper providesDateHelper() {
        return new DateHelper(mApp);
    }

    @Provides
    @Singleton
    public PersistentConfig providesPersistentConfig() {
        return new PersistentConfig(mApp);
    }

    @Provides
    @Singleton
    public OttoBus providesOttoBus() {
        return new OttoBus();
    }
}

public class Application extends MultiDexApplication {
    private ApplicationComponent mApplicationComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        mApplicationComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this))
                .build();
        mApplicationComponent.inject(this);
    }

    public static Application getApp(@NonNull Context context) {
        return (Application) context.getApplicationContext();
    }

    public static ApplicationComponent getApplicationComponent(@NonNull Context context) {
        return getApp(context).getApplicationComponent();
    }
}

当我想注入 ApplicationComponent 时到处都是

例如MainActivity

public class MainActivity extends AppCompatActivity {
    @Inject
    PersistentConfig mPersistentConfig;

    @Inject
    OttoBus mOttoBus;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        Helper.manageRotation(this);
        super.onCreate(null);
        setContentView(R.layout.main_layout);
        Application.getApplicationComponent(this).inject(this);
    }
}

Application.getApplicationComponent(context).inject(this);

第一个问题: 我真的很困惑 interface ApplicationComponent 必须提供 all activities/fragments/services (等) 我想在其中使用注入。但是我不能使用像 Activity / Fragment 这样的通用对象。还是我真的脱离现实,不明白Dagger2是如何工作的?

因为这对于包含大约 50 多个活动和大量 fragments/services...

的项目来说真的很疯狂
@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
    void inject(@NonNull Application app);
    void inject(@NonNull MainActivity object);
    void inject(@NonNull DispatcherActivity object);
    void inject(@NonNull DateTimeHelper object);
    void inject(@NonNull DatabaseHelper object);
    void inject(@NonNull LandingPageActivityFragment object);
    void inject(@NonNull RedirectActivity object);
    void inject(@NonNull CategoryFragment object);
    void inject(@NonNull BaseModuleFragment object);
    void inject(@NonNull NotificationHelper object);
    void inject(@NonNull RecordAdapter object);
    void inject(@NonNull PagingProvider object);
    void inject(@NonNull FilterDialog object);
    ... next 100+ injections?
}

我说,这不可能是真的...

第二个问题: 当我不能像 void inject(@NonNull NotificationHelper<? extends GenericObject> object); 那样使用它时,我如何提供注入泛型 类,因为它需要特定的对象。所以我必须将所有这些对象写在 ApplicationComponent 中而不是使用 ? 符号?

这不仅仅是疯狂 :(。也许最好继续使用 RoboGuice,它对开发人员更友好,不需要产生这种开销并手动检查每个注入的对象?当我忘记将它们添加到此列表时,我将在运行时得到 NPE(当我不对其进行大量测试时,它会使客户崩溃)。

当无法使用像 Activity / Fragment / Service.

这样的通用对象时,手动编写比列出所有对象要快得多

有没有更好的解决方案,当我不想使用相同的泛型 BaseActivity 时,它将注入 ApplicationModule 的每个部分,每个 activity 将被这个巨大的 BaseActivity?

这个问题有投诉的方面,但要尝试回答:

I'm really confused about interface ApplicationComponent which must provide all activities/fragments/services (etc) where I want to use injection. But I can't use generic objects like Activity / Fragment. Or am I really out of reality and don't understand how Dagger2 works?

确实,这就是 Dagger 2 的工作原理;它必须在注入器(组件)内静态提供注入目标的类型,并且不能使用 'generic'(协变)类型。 Dagger 2 这样做是为了维护一个 100% 静态的 DI 框架。

请注意,您将 RecordAdapterDatabaseHelper 指定为注射部位。您可能不需要这样做,您应该尝试仅指定构造函数不可见的顶级对象(ActivityFragmentService)作为注入站点。其余对象应该能够通过用 @Inject 注释它们的依赖关系并在 Module.

中指定它们的依赖关系(如果有的话)来构造。

Maybe better stay with RoboGuice which is much more developer friendly and don't need make this overhead and manual check every injected objects

是的,Roboguice 更友好,您不必担心指定注入目标。但是,请考虑 Roboguice 中的以下内容: 1. 错误设置对象图时得到的 'red stacktrace of death' 2. 您无法通过 Find Usages 查看您的项目中实际使用了哪些接口实现,也可以是 'developer unfriendly'

Is there a better solution, when I don't want use same generic BaseActivity which will inject every part of ApplicationModule and every activity will be extended by this huge BaseActivity?

好吧,这取决于您使用的依赖项和位置。如果你有一个小的依赖列表,你想在每个地方 注入,这可能是最好的解决方案,即制作一个 BaseActivity 接收这些注入并使其可用你所有的子类。或者,您可以使用子组件和模块来划分您的对象图,以便您可以将 consumers/injection 目标与正确的模块组合在一起。那么您就不需要一个 'god' 组件来列出所有注射部位。

Second question: How I can provide to inject generic classes, when I can't use it like void inject(@NonNull NotificationHelper object); because it require specific object. So I must write all this objects inside ApplicationComponent and not use ? notation?

是的,您必须提供注入目标的不变类型。我不确定您的 NotificationHelper<String> 是否是顶级类型。为什么不在注入 FragmentActivityService 时通过对象图注入它?

如果它绝对必须是一个注入目标,你将需要子类化:NotificationHelper<String>Notification<Integer>成为StringNotificationHelper extends NotificationHelper<String>IntegerNotficationHelper extends NotificationHelper<Integer>.这是 Clean Code 一书中推荐的做法。

你不需要把所有的注入点都写在 ApplicationComponent 里面,你可以创建与项目中依赖项的消费模式相对应的子组件。

(披露:作为目前正在尝试将项目从 Roboguice 迁移到 Dagger 2 的人,我对您的投诉表示同情)

谢谢,我们按照您一周前的描述解决了它。使用注入的每个对象。

更好的解决方案是不要只使用 inject 而要使用复杂的名称。为什么?因为这将有助于解决为什么某些对象没有被注入(你知道,base 类 等等)。

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
    void injectApplication(@NonNull Application app);
    void injectMainActivity(@NonNull MainActivity object);
    void injectDispatcherActivity(@NonNull DispatcherActivity object);
    ...
}

我们最终使用通用性 UtilityWrapper,如下所述:https://medium.com/@patrykpoborca/dagger-2-and-base-classes-generics-and-presenter-injection-7d82053080c#.b58ykd4cm