我的问题类似于this。
例如,我有一个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
而不是注入视图,我就不会收到任何编译器投诉。
谢谢!
答案 0 :(得分:27)
View
对象 View
的子类不是Dagger 2注射的良好目标。 View
对象是用来绘制的,而不是其他对象,因此称为“视图”。 View
的构造函数应该明确这一点;它们用于从XML中指定的属性中扩展View
个对象。换句话说,View
对象应该能够在layout.xml
文件中指定,在生命周期的适当位置膨胀,然后使用findViewById(int id)
,Butterknife获取或数据绑定。通过这种方式,最佳自定义View
对象不会依赖。
如果要链接View
和模型层中的某些数据,标准模式是编写适用于RecyclerView
和ListView
的适配器。如果无法做到这一点,那么使用setter(例如setData()
)比从构造函数中的模型层传递依赖项或从View
的一个生命周期方法中请求注入更可取。
如果您使用LiveData
类在活动或片段中注入AndroidInjector
对象,则无需执行任何操作即可提供正确的Context
。这解释了您的评论“如果将CustomLiveData注入到MainActivity而不是视图中,我不会收到任何编译器投诉。”
将LiveData
对象注入活动后,请使用上述方法之一(适配器或设置器)将数据与自定义View
相关联。请参阅Google Android架构示例here,其中使用Dagger 2注入模型图层中的元素,然后使用ListView
和findViewById
setAdapter()
相关联
链接到Dagger 2问题,其中讨论了View
对象的注入:
答案 1 :(得分:1)
您的Dagger层次结构如下所示:
appcomponent
- &gt; activitycomponent
您尝试在视图中注入活动context
,这取决于appcomponent
。{/ p>
这是不可能的,因为没有方法可以在appcomponent
中提供活动上下文。相反,在内部视图中,您应该检索活动(例如使用getContext
),从中提取activitycomponent
,然后只注入CustomLiveData
。