简体   繁体   中英

Dagger 2.11 Dependency Cycle

Using Dagger 2.11, the following code returns "Error:[dagger.android.AndroidInjector.inject(T)] Found a dependency cycle:". This is happening because the provideApp method has the argument "App app". If I remove it and do a dirty hack that provides the application instance directly, the code compiles and works.

From examples I've seen before, it used to be common practice to keep an instance of the application in the module and using that for other providers, but since this module class is now abstract, this doesn't work as the @Provide methods need to be static.

How can I solve this?

@Module(includes = AndroidInjectionModule.class)
public abstract class AppModule {

     @Provides
     @Singleton
     static App provideApp(App app) {
        return app;
     }

     @Provides
     static Authenticator provideAuthenticator(App app) {
         return new AuthenticatorImpl(app);
     }
}

EDIT:

What I need to achieve is basically this behaviour:

@Module(includes = AndroidInjectionModule.class)
public class AppModule {

    private App application;

    AppModule(App app) {
        application = app;
    }

    @Provides
    Authenticator provideAuthenticator() {
        return new AuthenticatorImpl(application);
    }
}

However, this doesn't work since the AppModule is now an abstract class and the app wouldn't compile if I use @Provides Authenticator provideAuthenticator() without the static keyword. If I use the static keyword, then I can't access the non-static application field.

Your code:

 @Provides
 @Singleton
 static App provideApp(App app) {
    return app;
 }

means "provide App using App as a dependency". In other words, you want to provide App but you need App first. Hence your cycle.

The best solution to this problem is to follow the Rule of Demeter and not to provide the Application singleton at all.

Why does your AuthenticatorImpl need to know the concrete type of your Application subclass? I bet you can refactor that class so that Application is no longer a direct dependency for it - perhaps you merely need a Context. If you merely need singletons at app-scope, you can simply make a module with @Singleton @Provides methods and install it in your application component.

If, after all this, you find you must @Provide your subclass you can create a new module that doesn't include any others:

@Module //don't include other modules here
class AppModule {

    private final App app;

    public AppModule(App app) {
        this.app = app;
    }

    @Provides
    @Singleton
    App app() {
        return app;
    }
} 

And install it in your app-level component:

    //inside your App class

    DaggerAppComponent.builder()
            .appModule(new AppModule(this))
            .build()
            .inject(this);

You would not need the AppModule if you implemented the following in your Application :

public class App extends DaggerApplication {
    private AndroidInjector<App> appInjector;

    @dagger.Component(modules = {
            AndroidSupportInjectionModule.class,
            AppModule.class
    })
    public interface Component extends AndroidInjector<App> {
        @dagger.Component.Builder
        abstract class Builder extends AndroidInjector.Builder<App> {}
    }

@Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
        return DaggerApp_Component
                .builder()
                .username("Username from application")
                .create(this);
    }
}

Now App will be a dependency on the global scope and can be used in every module linked to the @Component .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM