我们使用了 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();
}
}
当我想注入(inject) 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
真的很困惑它必须提供我想要使用注入(inject)的所有 Activity/fragment/服务(等)。但我不能使用像 Activity / Fragment
这样的通用对象。还是我真的脱离了现实,不明白Dagger2是如何工作的?
因为这对于拥有大约 50 多个 Activity 和大量 fragment/服务的项目来说真的很疯狂......
@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);
那样使用它时,我如何提供注入(inject)泛型类?因为它需要特定的对象。所以我必须将所有这些对象写在 ApplicationComponent
内并且不使用 ?
符号?
这不仅仅是疯狂:(。也许最好还是使用 RoboGuice,它对开发人员更加友好,并且不需要进行这种开销并手动检查每个注入(inject)的对象?当我忘记将它们添加到此列表中时,我会在运行时获取NPE
(当我不会对其进行大量测试时,它会让客户崩溃)。
当无法使用像Activity / Fragment / Service
这样的通用对象时,手动编写比创建所有对象的列表要快得多。 .
当我不想使用相同的通用 BaseActivity
时,是否有更好的解决方案它将注入(inject) 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 的工作原理;如果您必须在注入(inject)器(组件)内静态提供注入(inject)目标的类型,并且不能使用“通用”(协变)类型。 Dagger 2 这样做是为了保持 100% 静态的 DI 框架。
请注意,您正在指定 RecordAdapter
和DatabaseHelper
作为注入(inject)部位。您可能不需要这样做,您应该尝试仅指定构造函数不可见的顶级对象( Activity
、 Fragment
和 Service
)作为注入(inject)站点。其余对象应该能够通过使用 @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 更友好,因为您不必担心指定注入(inject)目标。但是,请在 Roboguice 中考虑以下因素: 1. 当您错误地设置对象图时,您会得到“红色死亡堆栈跟踪” 2. 事实上,您无法通过“查找用法”查看项目中实际使用了哪些接口(interface)实现,这也可能是“对开发人员不友好”
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?
嗯,这取决于您正在使用哪些依赖项以及在何处使用。如果您有一小部分依赖项想要到处注入(inject),这可能是最好的解决方案,即创建 BaseActivity
接收这些注入(inject)并使其可供所有子类使用。或者,您可以使用子组件和模块来划分对象图,以便可以将消费者/注入(inject)目标与正确的模块分组在一起。那么您就不需要拥有一个列出所有注入(inject)部位的“上帝”组件。
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?
是的,您必须提供注入(inject)目标的不变类型。我不确定你的NotificationHelper<String>
是否是顶级类型。当您注入(inject) Fragment
时,为什么不通过对象图注入(inject)它? , Activity
或Service
?
如果它绝对必须是一个注入(inject)目标,您将需要子类化:NotificationHelper<String>
和Notification<Integer>
成为StringNotificationHelper extends NotificationHelper<String>
, IntegerNotficationHelper extends NotificationHelper<Integer>
。这是《Clean Code》一书中推荐的做法。
您不需要将所有注入(inject)站点都写入ApplicationComponent内,您可以创建与项目中依赖项的消费模式相对应的子组件。
(披露:作为目前正在尝试将项目从 Roboguice 迁移到 Dagger 2 的人,我对您的投诉表示同情)
关于android - Dagger2 注入(inject)大量 Activity/fragment/服务(可能获得大量 NPE),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40206831/