【问题标题】:CustomView dependency injection with dagger 2 (within activity scope)使用 Dagger 2 的 CustomView 依赖注入(在活动范围内)
【发布时间】:2017-06-30 10:20:18
【问题描述】:

我的问题类似于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 而不是注入视图,我不会收到任何编译器投诉。 谢谢!

【问题讨论】:

  • 您在将CustomLiveData 注入Custom 视图时是否遇到任何编译错误?请将其与您的问题一起发布。
  • 消息包含在 CustomView 部分中。请参阅“//获取@com.di.qualifiers.ActivityContext android.content.Context 不能......”
  • 你能发@ActivityContext吗?

标签: android dependency-injection dagger-2 dagger


【解决方案1】:

tl;dr 不要在自定义 View 对象中注入模型层依赖项

View 的子类不是 Dagger 2 注入的好目标。 View 对象是用来绘制的,而不是必须绘制的,因此得名“视图”。 View 的构造函数应该说明这一点;它们被设计用于从 XML 中指定的属性中膨胀 View 对象。换句话说,View 对象应该能够在layout.xml 文件中指定,在生命周期中的适当点进行膨胀,然后使用findViewById(int id)Butterknife 或数据绑定获得。这样,最好的自定义 View 对象就没有依赖关系了。

如果您想链接View 和来自模型层的一些数据,标准模式是编写一个类似RecyclerViewListView 的适配器。如果这是不可能的,则使用 setter(例如,setData())比在构造函数中从模型层传递依赖项或从 View 的生命周期方法之一中请求注入更可取。

如果您使用 AndroidInjector 类将 LiveData 对象注入到 Activity 或 Fragment 中,则无需您执行任何操作即可提供正确的 Context。这解释了您的评论“如果将 CustomLiveData 注入 MainActivity 而不是注入视图,我不会收到任何编译器投诉。”

LiveData 对象注入Activity 后,使用上述方法之一(适配器或设置器)将数据与您的自定义View 关联。请参阅 Google Android 架构示例 here,其中模型层的元素使用 Dagger 2 注入,然后使用 findViewByIdsetAdapter()ListView 关联

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

https://github.com/google/dagger/issues/720

【讨论】:

  • 我正在构建 AR 视图,它需要一个类,该类需要处理传感器值、计算和过滤的类以及获取位置的类。我不应该将这些类注入到扩展 View 或 SurfaceView 等的类中吗?
  • @Thracian 我仍然认为如果可能的话,你应该尝试编写一个适配器
  • 我没有将传感器值或位置值显示为列表。需要传感器和位置输出来将地图上兴趣点的位置转换为屏幕。膨胀的视图使用带有上下文和属性的构造函数。我想知道我是否应该进行方法注入来注入传感器和位置管理器类。
  • 我还需要除 ARView 之外的 Activity 中的位置和传感器值。
  • 如果视图不是匕首的好目标,那么匕首不是注射的好工具。因为 target 应该是独立的,并且在任何地方注入任何东西都没有特殊限制。
【解决方案2】:

您的 Dagger 层次结构如下所示: appcomponent -> activitycomponent

您尝试在视图中注入活动context,这直接依赖于appcomponent

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多