带匕首2的CustomView依赖项注入(在活动范围内) [英] CustomView dependency injection with dagger 2 (within activity scope)

查看:75
本文介绍了带匕首2的CustomView依赖项注入(在活动范围内)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题类似于

例如,我有一个 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类的其余部分:

And here is the rest of DI classes:

@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 注入到<$ c $中,我不会收到任何编译器投诉。 c> MainActivity 代替进入视图。
谢谢!

Note, that I don't get any compiler complaints if CustomLiveData is injected into MainActivity instead into the view. Thanks!

推荐答案

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


View 的子类不是Dagger 2注入的良好目标。 View 对象用于绘制而不是必须绘制,因此名称为 view。 View 应该明确这一点;它们旨在从XML中指定的属性中扩展 View 对象。换句话说,应该能够在 layout.xml 文件中指定一个 View 对象,并在适当的位置进行充气指向生命周期,然后使用 findViewById(int id) Butterknife 或数据绑定。这样,最好的自定义 View 对象就没有依赖性。

tl;dr Don't inject model layer dependencies inside custom View objects

Subclasses of View are not good targets for Dagger 2 injection. View objects are meant to be drawn and not must else, hence the name "view". The constructors for 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 or data binding. In this way, the best custom View objects take no dependencies.

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

If you want to link a View and some data from the model layer, the standard pattern is to write an Adapter like those for RecyclerView and ListView. If this is not possible, using a setter (e.g., setData()) is preferable to passing dependencies from the model layer in the constructor or requesting injection from within one of the lifecycle methods of the View.

如果相反,您将 LiveData 对象注入其中使用 AndroidInjector 类的活动或片段,将提供正确的 Context ,而您无需执行任何操作。这解释了您的评论如果将CustomLiveData注入MainActivity而不是视图中,我不会收到任何编译器投诉。

If instead you inject your LiveData object inside an Activity or Fragment using the AndroidInjector class the correct Context will be provided without you having to do anything. This explains your comment "I don't get any compiler complaints if CustomLiveData is injected into MainActivity instead into the view."

一旦注入了 LiveData, 对象放入活动中,请使用上述方法之一(适配器或设置器)将数据与您的自定义 View 关联。请参阅Google Android体系结构示例此处使用Dagger 2注入模型层中的元素,然后将其与 ListView 使用 findViewById setAdapter()

Once you have injected the LiveData object into the Activity, use one of the above methods (an adapter or a setter) to associate the data with your custom View. See the Google Android Architecture example here where elements from the model layer are injected using Dagger 2 and then associated with a ListView using findViewById and setAdapter()

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

Link to the Dagger 2 issue where injection of View objects is discussed:

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

这篇关于带匕首2的CustomView依赖项注入(在活动范围内)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆