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 框架。
请注意,您将 RecordAdapter
和 DatabaseHelper
指定为注射部位。您可能不需要这样做,您应该尝试仅指定构造函数不可见的顶级对象(Activity
、Fragment
和 Service
)作为注入站点。其余对象应该能够通过用 @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>
是否是顶级类型。为什么不在注入 Fragment
、Activity
或 Service
时通过对象图注入它?
如果它绝对必须是一个注入目标,你将需要子类化: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
我们使用了 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 框架。
请注意,您将 RecordAdapter
和 DatabaseHelper
指定为注射部位。您可能不需要这样做,您应该尝试仅指定构造函数不可见的顶级对象(Activity
、Fragment
和 Service
)作为注入站点。其余对象应该能够通过用 @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>
是否是顶级类型。为什么不在注入 Fragment
、Activity
或 Service
时通过对象图注入它?
如果它绝对必须是一个注入目标,你将需要子类化: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