Android 使用dagger 2的CustomView依赖项注入(在活动范围内)

Android 使用dagger 2的CustomView依赖项注入(在活动范围内),android,dependency-injection,dagger-2,dagger,Android,Dependency Injection,Dagger 2,Dagger,我的问题类似于 例如,我有一个LiveData实现: public class CustomLiveData extends LiveData<SomeEvent> { @Inject public CustomLiveData(@ActivityContext Context context) { //.... } } 公共类CustomLiveData扩展了LiveData{ @注入 公共CustomLiveData(@Activit

我的问题类似于

例如,我有一个
LiveData
实现:

public class CustomLiveData extends LiveData<SomeEvent> {

    @Inject
    public CustomLiveData(@ActivityContext Context context) {
        //....
    }

}
公共类CustomLiveData扩展了LiveData{
@注入
公共CustomLiveData(@ActivityContext上下文){
//....
}
}
我要将其注入到自定义视图中:

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);
   }
}
公共类CustomView扩展了视图{
@注入
SomeApplicationProviderAnyProvider;
@注入
CustomLiveData数据提供者;
//如果没有@Provides注释方法,则无法提供get@com.di.qualifiers.ActivityContext android.content.Context。
//@com.di.qualifiers.ActivityContext android.content.Context被注入com.repositories.CustomLiveData。(上下文)
//com.repositories.CustomLiveData在com.ui.CustomView.dataProvider com.ui.CustomView在
//com.di.ApplicationComponent.inject(视图)
公共自定义视图(上下文){this(上下文,null);}
公共自定义视图(上下文属性集属性){
超级(上下文,attrs);
//适用于应用程序提供商
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{
}
@ApplicationScope
@组成部分(
modules={AndroidInjectionModule.class,
ActivityBuilder.class
})
公共接口应用程序组件扩展了AndroidJector{
无效注入(MyApp应用程序);
无效注入(自定义视图);
@组件生成器
抽象类生成器扩展了Androidjector.Builder{
公共抽象应用程序组件构建();
}
}
@活动范围
@模块(子组件=MainActivitySubcomponent.class)
公共抽象类ActivityBuilder{
@束缚
@英托马普
@ActivityKey(MainActivity.class)

abstract AndroidJector.Factory您的匕首层次结构如下所示:
appcomponent
->
activitycomponent

您尝试在视图内部注入活动
context
,该视图直接依赖于
appcomponent

这是不可能的,因为没有方法可以在
appcomponent
中提供活动上下文。相反,在视图内部,您应该检索活动(例如使用
getContext
),从中提取
activitycomponent
,然后注入
CustomLiveData

tl;dr不在自定义
视图
对象中注入模型层依赖项
View
的子类不是匕首2注射的好目标。
View
对象是要绘制的,而不是必须绘制的,因此命名为“View”。的构造函数应该明确这一点;它们设计用于从XML中指定的属性膨胀
视图
对象。换句话说,
视图
对象应该能够在
layout.XML
文件中指定,在生命周期中的适当点膨胀,然后使用
findViewById获得(int id)
或数据绑定。这样,最好的自定义
视图
对象就不需要依赖项

如果要链接
视图
和模型层中的一些数据,标准模式是编写一个适配器,类似于
RecyclerView
ListView
的适配器。如果不可能,请使用setter(例如,
setData()
)最好是从构造函数中的模型层传递依赖项,或者从
视图的生命周期方法之一请求注入

相反,如果您使用
androidjector
类将
LiveData
对象注入到活动或片段中,则无需执行任何操作即可提供正确的
上下文。这解释了您的注释“如果将CustomLiveData注入MainActivity而不是视图中,我不会收到任何编译器投诉。”

LiveData
对象注入活动后,使用上述方法之一(适配器或setter)要将数据与自定义的
视图关联,请参见Google Android架构示例,其中使用Dagger 2注入模型层的元素,然后使用
findViewById
setAdapter()与
列表视图关联

链接到Dagger 2问题,其中讨论了
视图
对象的注入:


CustomLiveData
注入
Custom
视图时,您是否遇到编译错误?请将其与您的问题一起发布。该消息包含在CustomView部分。请参阅“//Getting@com.di.qualifiers.ActivityContext android.content.Context无法…”。。。。。"你可以发布
@ActivityContext
?我正在构建AR视图,它需要一个类,该类需要处理传感器值、计算和过滤的类,还需要一个类来获取位置。我不应该将这些类注入到扩展View或SurfaceView等的类中吗?@Thracian我仍然认为你应该尝试编写一个适配器,如果需要的话可能我不将传感器值或位置值显示为列表。传感器和位置输出是将地图上的兴趣点位置转换为屏幕所必需的。视图使用具有上下文和属性的构造函数。我想知道是否应该进行方法注入以注入传感器和位置管理器类。我还需要位置和传感器值如果视图不是匕首的好目标,那么匕首就不是注射的好工具。因为目标应该是独立的,并且在任何地方注射任何东西都没有特殊的限制。