私の質問は 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
に注入された場合、コンパイラの問題は発生しません。ありがとう!
View
オブジェクト内にモデルレイヤーの依存関係を挿入しませんView
のサブクラスは、ダガー2インジェクションの適切なターゲットではありません。 View
オブジェクトは描画するためのものであり、他のものを描画する必要はないため、「ビュー」という名前です。 View
のコンストラクタは、これを明確にする必要があります。これらは、XMLで指定された属性からView
オブジェクトを膨らませるように設計されています。つまり、View
オブジェクトを_layout.xml
_ファイルで指定し、ライフサイクルの適切な時点で膨張させ、findViewById(int id)
を使用して取得できるようにする必要があります- バターナイフ またはデータバインディング。このように、最高のカスタムView
オブジェクトは依存関係を持ちません。
View
とモデルレイヤーの一部のデータをリンクする場合、標準パターンはRecyclerView
とListView
のようなアダプターを作成することです。これが不可能な場合は、コンストラクターのモデルレイヤーから依存関係を渡すか、View
のライフサイクルメソッドの1つからインジェクションを要求するよりも、セッター(setData()
)を使用することをお勧めします。 。
代わりに、LiveData
クラスを使用してアクティビティまたはフラグメント内にAndroidInjector
オブジェクトを挿入すると、何もしなくても正しいContext
が提供されます。これは、「CustomLiveDataがビューではなくMainActivityに注入された場合、コンパイラの問題は発生しない」というコメントを説明しています。
LiveData
オブジェクトをアクティビティに注入したら、上記のメソッドの1つ(アダプターまたはセッター)を使用して、データをカスタムView
に関連付けます。 Googleをご覧くださいAndroidアーキテクチャの例 こちら ここでは、モデルレイヤーの要素がDagger 2を使用して注入され、次にListView
と関連付けられますfindViewById
およびsetAdapter()
View
オブジェクトの注入が説明されているDagger 2の問題へのリンク:
Dagger階層は次のようになります:appcomponent
-> activitycomponent
context
に直接依存するアクティビティappcomponent
をビュー内に挿入しようとしています。
appcomponent
にアクティビティコンテキストを提供できるメソッドがないため、これは不可能です。代わりに、ビュー内で(getContext
を使用して)アクティビティを取得し、そこからactivitycomponent
を抽出して、CustomLiveData
を注入する必要があります。