web-dev-qa-db-ja.com

ダガー2エラー:実際には@Injectアノテーションが付けられていますが、依存関係は「@Injectコンストラクターなしでは提供できません」

Dagger 2の使用を開始しましたが、バグのように見える奇妙な問題に直面しました。

3つのモジュールがあり、それらは1つのサブコンポーネントに構成されています。このサブコンポーネントは、さらに高いレベルのコンポーネントを拡張/拡張します。

サブコンポーネントは非常に単純です。モジュールと単一の注入ポイントの組み合わせだけです。

@Singleton
@Subcomponent(
        modules = {
                NavigationDrawerModule.class,
                NavigationListModule.class,
                SwitcherModule.class
        }
)
public interface NavigationDrawerComponent {


    NavigationDrawerFragment inject(NavigationDrawerFragment object);

}

最初のモジュールは次のようになります-一般的なフラグメントレベルの依存関係を提供します:

@Module
public class NavigationDrawerModule {

    private final Activity activity;
    private final View rootView;
    private final LoaderManager loaderManager;

    public NavigationDrawerModule(Activity activity, View rootView, LoaderManager loaderManager) {
        this.activity = activity;
        this.rootView = rootView;
        this.loaderManager = loaderManager;
    }

    @Provides @Singleton EventBus provideLocalBus() {
        return EventBus.builder().build();
    }

    @Provides @Singleton View provideViewRoot() {
        return rootView;
    }

    @Provides @Singleton LoaderManager provideLoaderManager() {
        return loaderManager;
    }

    @Provides @Singleton Context provideContext() {
        return activity;
    }
}

2番目のモジュールは次のようになります。プレゼンター/コントローラーと、画面上のUIのサブセットに対する依存関係を提供します。

@Module
public class SwitcherModule {

    @Provides SwitchController provideSwitcherController(SwitchControllerImpl impl) {
        return impl;
    }

    @Provides SwitcherView provideSwitcherView(SwitcherViewImpl impl) {
        return impl;
    }

}

3番目のモジュール-UIのサブセット用の別のプレゼンター/コントローラー:

@Module
public class NavigationListModule {

    @Provides @Singleton NavigationListController provideNavigationListController(NavigationListControllerImpl impl) {
        return impl;
    }

    @Provides @Singleton NavigationListView provideNavigationListView(NavigationListViewImpl impl) {
        return impl;
    }
}

挿入されているフラグメントの関連部分:

@Inject SwitchController identitySwitchController;
@Inject SwitcherView identitySwitcherView;
@Inject NavigationListController navigationListController;
@Inject NavigationListView navigationListView;

NavigationListControllerImplは、次のコンストラクターを実装します。

@Inject
public NavigationListControllerImpl(Context ctx, EventBus bus) {
    this.ctx = ctx;
    this.bus = bus;
}

Dagger 2コンパイラからのエラーは次のとおりです。

error: ...sidenavigation.navigationlist.NavigationListControllerImpl cannot be provided without an @Inject constructor or from an @Provides-annotated method.
...sidenavigation.NavigationDrawerFragment.navigationListController
[injected field of type: ...sidenavigation.navigationlist.NavigationListController navigationListController]
...sidenavigation.navigationlist.NavigationListModule.provideNavigationListController(...sidenavigation.navigationlist.NavigationListControllerImpl impl)
[parameter: ...sidenavigation.navigationlist.NavigationListControllerImpl impl]

エラーは@ Inject-annotatedコンストラクターがないことを訴えますが、存在します!暗黙的なNavigationListControllerImplインスタンスの作成(@Provides- methodパラメーターを介して渡す)を明示的な(newで)に置き換えると、daggerは同じエラーについて不平を言い始めますが、現在はプレゼンターオブジェクトの2番目のエントリです同じモジュールなど。

この状況はすべて非常に奇妙に見えるので、より経験のあるDagger 2ユーザー(および開発者)からの意見を聞きたいと思います。

前もって感謝します!

43
dominus

Dagger 2のセットアップの何が問題なのかがわかったようです。コンポーネントとサブコンポーネントの両方で同じスコープを使用することはできません。サブコンポーネントの新しいスコープを定義するには、requiredです。私の場合、サブコンポーネント用に@Screenスコープを作成することになりました。

これはDagger 2の小さなですが非常に迷惑な欠陥だと思います。どうやらdagger-compilerは、子コンポーネントが依存関係として親コンポーネントで拡張されている場合、親コンポーネントと子コンポーネントの同じスコープに関するわかりやすくエラーを報告しているようです。ただし、親コンポーネントと子サブコンポーネントが同じスコープを共有している場合、コンパイラによって完全に誤解を招くエラーが報告されます。

ここにヒントを与えてくれてありがとう、@ lukas https://stackoverflow.com/a/30383088/80831 問題解決につながった。

15
dominus

親コンポーネント内のモジュールによって提供されるオブジェクトを、それに依存する他のコンポーネントに公開するのを忘れたため、この同じエラーが発生しました。

親コンポーネントの例:

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
    AppPref exposeAppPref(); /* my issue was caused by forgot this line,
the method name doesn't matter, what matters is the object type AppPref provided in the AppModule 
that you want it to be available in the component that declares this component as one of its dependencies*/
}

上記のコンポーネントを依存関係にするサンプルコンポーネント

@UserScope
@Component (dependencies = {AppComponent.class})
public interface ActivityComponent {
    void inject(MainActivity activity);
}

更新:

AppModule:

...
    @Provides
    @Singleton
    AppPref provideAppPref() {
        return appPref;
    }
...
48
s-hunter

GlobalComponentとサブコンポーネントNavigationDrawerComponentには異なるスコープが必要です。 GlobalComponentには@Singletonを使用し、サブコンポーネントには別のスコープを使用します。

それ以外の場合、GlobalScopeとサブコンポーネントに同じスコープを適用する場合、グローバルコンポーネントでもサブコンポーネントのモジュールを宣言する必要があります。

@Component(
        // modules from subcomponent must be declared here also
        modules = {NavigationListModule.class, 
                  SwitcherModule.class, 
                  NavigationDrawerModule.class,
                  ...}
)
@Singleton
public interface GlobalComponent {
   NavigationDrawerComponent plus(NavigationDrawerModule module);
}

ユースケースでは、コンポーネントの依存関係も使用できます。例えば:

@Component(
        dependencies = GlobalComponent.class,
        modules = {NavigationListModule.class, 
                  SwitcherModule.class, 
                  NavigationDrawerModule.class}
)
@YourOtherDaggerScope // @Singleton scope won't work here, it must be a different scope
public interface NavigationDrawerComponent extends GlobalComponent { // extend the parent component if you wish to get access to parent dependencies

   NavigationDrawerFragment inject(NavigationDrawerFragment object);
}
17
lukas

今日もこの問題に遭遇しました。私にとっては、注釈処理に問題がありました(Android St​​udio 2.2 with gradle 2.x)。

~~ apt ~~の代わりに、使用したannotationProcessorを使用しました

annotationProcessor 'com.google.dagger:dagger-compiler:2.6'

そして今、それは働いています。

4
Tobias

サブコンポーネントを作成しようとしたときに同じ問題に遭遇しましたが、Dagger 2.0.1では修正されているようです。

2
Kavi

多くの間違いについて同じ種類のエラーダガーレポートであるようです。私の場合、ターゲットインジェクションは、プレゼンターを提供するモジュールがインターフェイス(DemoContract.Presenter)のみを返す具象クラス(Presenter)を期待していました。

変更された

@Inject
public Presenter mDemoPresenter;  

to

@Inject
public DemoContract.Presenter mDemoPresenter;

プレゼンターを提供するモジュールは次のようになります。

@Module
public class DiDemoPresenterModule {
    private final DemoContract.View mView;

    DiDemoPresenterModule(MainActivity mView) {
        this.mView = mView;
    }

    @Provides
    public DemoContract.Presenter providesDemoPresenter(Repository repository) {
        return new DemoPresenter(repository, mView);
    }
}
1
cgr