72 votes

Dague: IllegalArgumentException: aucune fabrique d'injecteurs liée à la classe

Je suis nouveau sur le Poignard 2. J'ai 2 Activités, je veux utiliser injecté ViewModel pour les deux. Voici mon ViewModuleFactory :

@Singleton
public class ProductViewModelFactory implements ViewModelProvider.Factory {

    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

    @Inject
    public ProductViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
        this.creators = creators;
    }


    @SuppressWarnings("unchecked")
    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        Provider<? extends ViewModel> creator = creators.get(modelClass);
        if (creator == null) {
            for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
                if (modelClass.isAssignableFrom(entry.getKey())) {
                    creator = entry.getValue();
                    break;
                }
            }
        }
        if (creator == null) {
            throw new IllegalArgumentException("unknown viewmodel class " + modelClass);
        }
        try {
            return (T) creator.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Mon ViewModelModule:

@Module
abstract class ViewModelModule {
    @Binds
    @IntoMap
    @ViewModelKey(ProductListViewModel.class)
    abstract ViewModel bindProductListViewModel(ProductListViewModel listViewModel);

    @Binds
    @IntoMap
    @ViewModelKey(ProductDetailsViewModel.class)
    abstract ViewModel bindProductDetailsViewModel(ProductDetailsViewModel detailsViewModel);

    @Binds
    abstract ViewModelProvider.Factory bindViewModelFactory(ProductViewModelFactory factory);
}

Mon ViewModelKey pour la cartographie:

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
    Class<? extends ViewModel> value();
}

Mon ActivityModule :

@Module
public abstract class ActivityModule {
    abstract ProductListActivity contributeProductListActivity();
    abstract ProductDetailsActivity contributeProductDetailsActivity();
}

Mon AppModule:

@Module
class AppModule {

@Provides
    @Singleton
    RedMartProductService provideRedMartProductService() {
        ........
    }

    @Provides
    @Singleton
    ProductListRepository provideProductListRepository(ProductListRepository repository) {
        return repository;
    }

    @Provides
    @Singleton
    ProductDetailsRepository provideProductDetailsRepository(ProductDetailsRepository repository) {
        return repository;
    }
}

Mon AppComponent:

@Singleton
@Component(modules = {AndroidInjectionModule.class, ActivityModule.class, AppModule.class})
public interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(Application application);

        AppComponent build();
    }

    void inject(MartApplication martApp);
}

Mon Application:

public class MartApplication extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public DispatchingAndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }
}

En Activité:

@Inject
ViewModelProvider.Factory viewModelFactory;
.......
AndroidInjection.inject(activity); // Throwing exception
ListViewModel = ViewModelProviders.of(this, viewModelFactory).get(ProductListViewModel.class);

Il est en train de lancer une exception à injecter:

java.lang.IllegalArgumentException: No injector factory bound for Class<com.mymart.ui.ProductListActivity>

Quelqu'un peut-il m'aider à identifier le problème dans mon code?

.......................................................................

Edit: j'ai essayé avec ContributesAndroidInjector comme par @azizbekian, mais il a entraîné d'erreur suivant sur la compilation:

    error: [dagger.android.AndroidInjector.inject(T)] Found a dependency cycle:
com.mymart.repository.ProductListRepository is injected at
com.mymart.di.AppModule.provideProductListRepository(repository)
com.mymart.repository.ProductListRepository is injected at
com.mymart.viewmodel.ProductListViewModel.<init>(productListRepository)
com.mymart.viewmodel.ProductListViewModel is injected at
com.mymart.di.ViewModelModule.bindProductListViewModel(listViewModel)
java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
com.mymart.viewmodel.ProductViewModelFactory.<init>(creators)
com.mymart.viewmodel.ProductViewModelFactory is injected at
com.mymart.di.ViewModelModule.bindViewModelFactory(factory)
android.arch.lifecycle.ViewModelProvider.Factory is injected at
com.mymart.ui.ProductListActivity.viewModelFactory
com.mymart.ui.ProductListActivity is injected at
dagger.android.AndroidInjector.inject(arg0)

Edit 2 Après tous les changements, je suis confronté à nouveau exception:

java.lang.RuntimeException: Unable to create application com.kaushik.myredmart.MartApplication: java.lang.IllegalStateException: com.kaushik.myredmart.di.AppModule must be set
                                                 at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4710)
                                                 at android.app.ActivityThread.-wrap1(ActivityThread.java)
                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
                                                 at android.os.Handler.dispatchMessage(Handler.java:102)
                                                 at android.os.Looper.loop(Looper.java:148)
                                                 at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                 at java.lang.reflect.Method.invoke(Native Method)
                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                              Caused by: java.lang.IllegalStateException: com.kaushik.myredmart.di.AppModule must be set
                                                 at com.kaushik.myredmart.di.DaggerAppComponent$Builder.build(DaggerAppComponent.java:180)
                                                 at com.kaushik.myredmart.di.AppInjector.init(AppInjector.java:30)
                                                 at com.kaushik.myredmart.MartApplication.onCreate(MartApplication.java:28)
                                                 at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1013)
                                                 at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4707)
                                                 at android.app.ActivityThread.-wrap1(ActivityThread.java) 
                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405) 
                                                 at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                 at android.os.Looper.loop(Looper.java:148) 
                                                 at android.app.ActivityThread.main(ActivityThread.java:5417) 
                                                 at java.lang.reflect.Method.invoke(Native Method)

126voto

andranikAzizbekyan Points 727

Je crois que vous avez oublié de mettre @ContributesAndroidInjector d'annotation:


    @Module
    public abstract class ActivityModule {
        @ContributesAndroidInjector
        abstract ProductListActivity contributeProductListActivity();
        @ContributesAndroidInjector
        abstract ProductDetailsActivity contributeProductDetailsActivity();
    }

Et comprennent ViewModelModule dans AppModule:


    @Module(includes = ViewModelModule.class)
    class AppModule {
        ...
    }


Voir ce code que vous avez écrit:

@Provides
@Singleton
ProductListRepository provideProductListRepository(ProductListRepository repository) {
    return repository;
}

Qu'attendez-vous d'arriver? Vous dites poignard "hey, dague, à chaque fois que je vous demande de me donner des ProductListRepository puis de créer(retour) cet objet à l'aide de ProductListRepository". Ce n'est pas barré.

Plus probablement que vous l'intention était "hey, dague, à chaque fois que je vous demande de me fournir une implémentation de l' ProductListRepository puis de créer(retour) cet objet à l'aide de ProductListRepositoryImpl":

@Provides
@Singleton
ProductListRepository provideProductListRepository(ProductListRepositoryImpl repository) {
    return repository;
}

Qui peut être substitué avec suivants:

@Binds
@Singleton
abstract ProductListRepository provideProductListRepository(ProductListRepositoryImpl repository);

-22voto

DivineChaos Points 49

L'utilisation de @contrubutesAndroidInjector nécessite un annotationProcessor supplémentaire.

Ajoutez cette ligne à votre fichier de construction Gradle:

 annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X