6

Je suis nouveau à Dagger 2. J'ai 2 activités, je veux utiliser ViewModel injecté pour les deux. Voici mon ViewModuleFactory:Dague: IllegalArgumentException: Aucun injecteur usine lié à la classe

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

Dans Activité:

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

Il jette une exception inject:

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

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

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

Modifier: J'ai essayé avec ContributesAndroidInjector comme @azizbekian, mais il a résulté erreur suivante sur la génération:

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 à 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) 

Répondre

10

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

 

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

et comprennent ViewModelModule dans les AppModule:

 

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

Voir ce code que vous avez écrit:

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

Que faites-vous Attendez-vous à arriver?Vous dites poignard "hé, dague, chaque fois que je vous demande de me fournir ProductListRepository puis créer (retourner) cet objet en utilisant ProductListRepository". Ça ne va pas marcher.

La plupart peut-être ce que vous aviez l'intention était « hey, poignard, chaque fois que je vous demande de me fournir une implémentation de ProductListRepository puis créer (retour) cet objet en utilisant ProductListRepositoryImpl »:

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

qui peut être substitué avec:

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

J'ai essayé. S'il vous plaît vérifier ma partie éditée ci-dessus et guide. –

+0

Je vous ai suivi, il en est résulté un cycle de dépendance. S'il vous plaît donnez votre avis. –

+0

Ajouté ci-dessus dans la partie éditée. S'il vous plaît vérifier @azizbekian –

-4

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

Ajouter cette ligne à votre fichier de construction gradle:

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