使用匕首 2 的 CustomView 依赖注入(在 activity 范围内)
CustomView dependency injection with dagger 2 (within activity scope)
我的问题类似于。
例如,我有一个 LiveData
实现:
public class CustomLiveData extends LiveData<SomeEvent> {
@Inject
public CustomLiveData(@ActivityContext Context context) {
//....
}
}
我想注入自定义视图:
public class CustomView extends View {
@Inject
SomeApplicationProvider anyProvider;
@Inject
CustomLiveData dataProvider;
// Getting @com.di.qualifiers.ActivityContext android.content.Context cannot be provided without an @Provides-annotated method.
// @com.di.qualifiers.ActivityContext android.content.Context is injected at com.repositories.CustomLiveData.<init>(context)
// com.repositories.CustomLiveData is injected at com.ui.CustomView.dataProvider com.ui.CustomView is injected at
// com.di.ApplicationComponent.inject(view)
public CustomView(Context context) { this(context, null); }
public CustomView(Context AttributeSet attrs) {
super(context, attrs);
// Works ok for application provider
Application.getComponent(context).inject(this);
}
}
这是 DI 的其余部分 类:
@ApplicationScope
@Component(
modules = {AndroidInjectionModule.class,
ActivityBuilder.class
})
public interface ApplicationComponent extends AndroidInjector<MyApp> {
void inject(MyApp application);
void inject(CustomView view);
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<MyApp> {
public abstract ApplicationComponent build();
}
}
@ActivityScope
@Module (subcomponents = MainActivitySubcomponent.class)
public abstract class ActivityBuilder {
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity>
bindActivityInjectorFactory(MainActivitySubcomponent.Builder builder);
//...
}
@Subcomponent(modules = {MainActivityModule.class})
public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
}
}
@ActivityScope
@Module
public class MainActivityModule {
@Provides
@ActivityContext
public Context provideActivityContext(MainActivity activity) {
return activity;
}
// Seems to be wrong or not enough!?
@Provides
public CustomLiveData provideCustomLiveData(@ActivityContext Context context) {
return new CustomLiveData(context);
}
}
@Qualifier
public @interface ActivityContext{
}
请注意,如果将 CustomLiveData
注入到 MainActivity
而不是注入到视图中,我不会收到任何编译器投诉。
谢谢!
您的 Dagger 层次结构如下所示:
appcomponent
-> activitycomponent
您尝试在视图中注入 activity context
,这直接取决于 appcomponent
。
这是不可能的,因为没有方法可以在 appcomponent
中提供 activity 上下文。相反,在视图内部,您应该检索 activity(例如使用 getContext
),从中提取 activitycomponent
,然后才注入 CustomLiveData
。
tl;dr 不要在自定义 View
对象中注入模型层依赖项
View
的 Subclass 不是 Dagger 2 注入的好目标。 View
对象是用来绘制的,而不是必须绘制的,因此得名“视图”。 View
should make this clear; they are designed for inflating View
objects from attributes specified in XML. In other words, a View
object should be able to be specified in a layout.xml
file, inflated at the appropriate point in the lifecycle, and then obtained using findViewById(int id)
, Butterknife 或数据绑定的构造函数。通过这种方式,最好的自定义 View
对象不依赖。
如果你想 link 一个 View
和来自模型层的一些数据,标准模式是为 RecyclerView
和 ListView
编写一个适配器.如果这不可能,则使用 setter(例如 setData()
)比在构造函数中从模型层传递依赖项或从 [=10= 的生命周期方法之一请求注入更可取].
如果您使用 AndroidInjector
class 将 LiveData
对象注入到 Activity 或 Fragment 中,将提供正确的 Context
而无需您做任何事。这解释了您的评论“如果将 CustomLiveData 注入 MainActivity 而不是注入视图,我不会收到任何编译器投诉。”
将 LiveData
对象注入 Activity 后,使用上述方法之一(适配器或 setter)将数据与您的自定义 View
。请参阅 Google Android 架构示例 here,其中模型层的元素使用 Dagger 2 注入,然后使用 findViewById
和 [=31 与 ListView
相关联=]
Link 到 Dagger 2 问题,其中讨论了 View
对象的注入:
我的问题类似于
例如,我有一个 LiveData
实现:
public class CustomLiveData extends LiveData<SomeEvent> {
@Inject
public CustomLiveData(@ActivityContext Context context) {
//....
}
}
我想注入自定义视图:
public class CustomView extends View {
@Inject
SomeApplicationProvider anyProvider;
@Inject
CustomLiveData dataProvider;
// Getting @com.di.qualifiers.ActivityContext android.content.Context cannot be provided without an @Provides-annotated method.
// @com.di.qualifiers.ActivityContext android.content.Context is injected at com.repositories.CustomLiveData.<init>(context)
// com.repositories.CustomLiveData is injected at com.ui.CustomView.dataProvider com.ui.CustomView is injected at
// com.di.ApplicationComponent.inject(view)
public CustomView(Context context) { this(context, null); }
public CustomView(Context AttributeSet attrs) {
super(context, attrs);
// Works ok for application provider
Application.getComponent(context).inject(this);
}
}
这是 DI 的其余部分 类:
@ApplicationScope
@Component(
modules = {AndroidInjectionModule.class,
ActivityBuilder.class
})
public interface ApplicationComponent extends AndroidInjector<MyApp> {
void inject(MyApp application);
void inject(CustomView view);
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<MyApp> {
public abstract ApplicationComponent build();
}
}
@ActivityScope
@Module (subcomponents = MainActivitySubcomponent.class)
public abstract class ActivityBuilder {
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity>
bindActivityInjectorFactory(MainActivitySubcomponent.Builder builder);
//...
}
@Subcomponent(modules = {MainActivityModule.class})
public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
}
}
@ActivityScope
@Module
public class MainActivityModule {
@Provides
@ActivityContext
public Context provideActivityContext(MainActivity activity) {
return activity;
}
// Seems to be wrong or not enough!?
@Provides
public CustomLiveData provideCustomLiveData(@ActivityContext Context context) {
return new CustomLiveData(context);
}
}
@Qualifier
public @interface ActivityContext{
}
请注意,如果将 CustomLiveData
注入到 MainActivity
而不是注入到视图中,我不会收到任何编译器投诉。
谢谢!
您的 Dagger 层次结构如下所示:
appcomponent
-> activitycomponent
您尝试在视图中注入 activity context
,这直接取决于 appcomponent
。
这是不可能的,因为没有方法可以在 appcomponent
中提供 activity 上下文。相反,在视图内部,您应该检索 activity(例如使用 getContext
),从中提取 activitycomponent
,然后才注入 CustomLiveData
。
tl;dr 不要在自定义 View
对象中注入模型层依赖项
View
的 Subclass 不是 Dagger 2 注入的好目标。 View
对象是用来绘制的,而不是必须绘制的,因此得名“视图”。 View
should make this clear; they are designed for inflating View
objects from attributes specified in XML. In other words, a View
object should be able to be specified in a layout.xml
file, inflated at the appropriate point in the lifecycle, and then obtained using findViewById(int id)
, Butterknife 或数据绑定的构造函数。通过这种方式,最好的自定义 View
对象不依赖。
如果你想 link 一个 View
和来自模型层的一些数据,标准模式是为 RecyclerView
和 ListView
编写一个适配器.如果这不可能,则使用 setter(例如 setData()
)比在构造函数中从模型层传递依赖项或从 [=10= 的生命周期方法之一请求注入更可取].
如果您使用 AndroidInjector
class 将 LiveData
对象注入到 Activity 或 Fragment 中,将提供正确的 Context
而无需您做任何事。这解释了您的评论“如果将 CustomLiveData 注入 MainActivity 而不是注入视图,我不会收到任何编译器投诉。”
将 LiveData
对象注入 Activity 后,使用上述方法之一(适配器或 setter)将数据与您的自定义 View
。请参阅 Google Android 架构示例 here,其中模型层的元素使用 Dagger 2 注入,然后使用 findViewById
和 [=31 与 ListView
相关联=]
Link 到 Dagger 2 问题,其中讨论了 View
对象的注入: