web-dev-qa-db-fra.com

Dague: IllegalArgumentException: aucune usine d'injecteur liée à la classe

Je suis nouveau sur Dagger 2. J'ai 2 activités, je veux utiliser ViewModel injecté 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 le mappage:

@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;
    }
}

Dans Activité:

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

Il lance une exception sur 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 selon @azizbekian, mais il en est résulté une erreur suivante sur la construction:

    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 fais face à une 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)
40
dev_android

Je crois que tu as oublié de mettre @ContributesAndroidInjector annotation:


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

Et incluez 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'espérez-vous qu'il se passe? Vous dites à la dague "hé, dague, chaque fois que je vous demande de me fournir ProductListRepository puis créez (retournez) cet objet en utilisant ProductListRepository". Ça ne va pas marcher.

Probablement ce que vous vouliez était "hé, dague, chaque fois que je vous demande de me fournir une implémentation de ProductListRepository puis créez (retournez) cet objet en utilisant ProductListRepositoryImpl":

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

Ce qui peut être remplacé par ce qui suit:

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