web-dev-qa-db-fra.com

Dagger2: Comment utiliser @Provides et @Binds dans le même module

J'utilise le nouveau Dagger2 (ver 2.11) et j'utilise les nouvelles fonctionnalités comme AndroidInjector et ContributesAndroidInjector. J'ai un sous-composant d'activité,

        @Module
        abstract class ActivityBuilderModule {
            @ContributesAndroidInjector(modules = 
                   {UserListModule.class, MainFragmentModule.class})
            @ActivityScope
            abstract MainActivity bindsMainActivity();

        }



  @Module
  public abstract class MainFragmentModule {
    @ContributesAndroidInjector
    @FragmentScope
    @FragmentKey(UserListFragment.class)
    abstract UserListFragment bindsUserListFragment();

}

Et le UserListModule fournit des dépendances pour le fragment. Certaines des dépendances que je veux simplement lier les instances et retourner, comme

 @Binds
 @ActivityScope
 abstract UserListView mUserListView(UserListFragment userListFragment);

Au lieu de simplement renvoyer la dépendance, comme

@Provides
@ActivityScope
UserListView mUserListView(UserListFragment userListFragment){
    return userListFragment;
}

Mon module contient également quelques méthodes @Provides. Pouvons-nous utiliser les méthodes @Binds Et @Provides Dans le même module? J'ai essayé comme indiqué ci-dessous

        @Module
        public abstract class UserListModule {
            @Provides
            @ActivityScope
            UserListFragment mUserListFragment() {
                return new UserListFragment();
            }

            @Binds
            @ActivityScope
            abstract UserListView mUserListView(UserListFragment userListFragment);

           // other provides and binds methods...
           ......
           .....

        }

Et c'est son erreur de lancement

Error:(22, 8) error: dagger.internal.codegen.ComponentProcessor was unable to process this interface because not all of its dependencies could be resolved. Check for compilation errors or a circular dependency with generated code.

Y a-t-il un moyen de faire ça?

19
user4260260

@Binds et @ContributesAndroidInjector les méthodes doivent être abstraites, car elles n'ont pas de corps de méthode. Cela signifie qu'ils doivent aller sur une interface ou une classe abstraite. @Provides les méthodes peuvent être static, ce qui signifie qu'elles peuvent aller sur des classes abstraites et des interfaces compilées en Java-8, mais non statiques ("instance") @Provides les méthodes ne fonctionnent pas sur les classes abstraites. Ceci est explicitement répertorié dans la FAQ Dagger, sous les sections "Pourquoi ne peut pas @Binds et instance @Provides les méthodes vont dans le même module? " et " Que dois-je faire à la place? " .

Si ton @Provides la méthode n'utilise pas l'état d'instance, vous pouvez le marquer static, et il peut aller sur une classe abstraite adjacente à votre @Binds méthodes. Sinon, pensez à mettre les liaisons comme @Binds et @ContributesAndroidInjector dans une classe distincte - peut-être une classe imbriquée statique - et en incluant celle-ci en utilisant l'attribut includes sur le @Module annotation.

24
Jeff Bowman

Un petit ajout à la solution de Jeff ci-dessus:

vous pouvez créer une interface interne au lieu d'une classe interne statique, comme ceci:

@Module(includes = AppModule.BindsModule.class)
public class AppModule {
    // usual non-static @Provides
    @Provides
    @Singleton
    Checkout provideCheckout(Billing billing, Products products) {
        return Checkout.forApplication(billing, products);
    }
    // interface with @Binds
    @Module
    public interface BindsModule {
        @Binds
        ISettings bindSettings(Settings settings);
    }
}
11
gordinmitya