1

J'ai un module nommé ViewModelModule. C'est là:Impossible de renvoyer la valeur null à partir d'une erreur @Novable @Provides de méthode

@Module(includes = RepositoryModule.class) 
public class ViewModelModule { 

    StepListFragment stepListFragment; 

    StepViewFragment stepViewFragment; 

    @Provides 
    public StepListFragment getStepListFragment() { 
     return stepListFragment; 
    } 

    @Provides 
    public StepViewFragment getStepViewFragment() { 
     return stepViewFragment; 
    } 

    public ViewModelModule(StepListFragment stepListFragment) { 
     this.stepListFragment = stepListFragment; 
    } 

    public ViewModelModule(StepViewFragment stepViewFragment) { 
     this.stepViewFragment = stepViewFragment; 
    } 

    @Provides 
    IngredientsViewModel ingredientsViewModel(StepListFragment stepListFragment, RecipesRepository repository) { 
     return ViewModelProviders.of(stepListFragment, new ViewModelProvider.Factory() { 
      @Override 
      public <T extends ViewModel> T create(Class<T> modelClass) { 
       return (T) new IngredientsViewModel(repository); 
      } 
     }).get(IngredientsViewModel.class); 
    } 

    @Provides 
    StepsViewModel stepsViewModel(StepViewFragment stepViewFragment, RecipesRepository repository) { 
     return ViewModelProviders.of(stepViewFragment, new ViewModelProvider.Factory() { 
      @Override 
      public <T extends ViewModel> T create(Class<T> modelClass) { 
       return (T) new StepsViewModel(repository); 
      } 
     }).get(StepsViewModel.class); 
    } 

} 

Tous mes composants ViewModules seront fournis. Mais pas au même moment.

J'ai un composant pour chaque fragment:

@Component(modules = {RepositoryModule.class, ContextModule.class, ViewModelModule.class}) 
public interface StepListComponent { 
    void inject (StepListFragment stepListFragment); 
} 



@Component(modules = {RepositoryModule.class, ContextModule.class, ViewModelModule.class}) 

public interface StepViewComponent { 
    void inject (StepViewFragment stepViewFragment); 
} 

Dans le premier moment StepListFragment est montré et j'instancier le composant comme ci-dessous:

DaggerStepListComponent.builder() 
     .applicationModule(new ApplicationModule(this.getActivity().getApplication())) 
     .contextModule(new ContextModule(this.getActivity())) 
     .viewModelModule(new ViewModelModule(this)).build().inject(this); 

Comme vous le voyez à la fin de la clause J'injecte le fragment. Ensuite, quand je commencerai l'autre fragment, je ferai la même chose. Mais quand il appelle le code ci-dessus je reçu cette erreur:

Caused by: java.lang.NullPointerException: Cannot return null from a [email protected] @Provides method 

Bien sur la cause d'erreur est le fait que je ne l'avais pas encore instanciée la StepViewFragment stepViewFragment; Mais je ne veux pas l'utiliser maintenant, cela ne causerait aucun problème.

J'ai essayé d'ajouter le @Nullable article comme suit:

@Nullable 
@Provides 
public StepListFragment getStepListFragment() { 
    return stepListFragment; 
} 

@Nullable 
@Provides 
public StepViewFragment getStepViewFragment() { 
    return stepViewFragment; 
} 

mais je reçois une erreur de compilation:

Error:(15, 10) error: StepListFragment is not nullable, but is being provided by @android.support.annotation.Nullable @Provides 
com.github.alexpfx.udacity.nanodegree.android.baking_app.step.master.steps.StepListFragment com.github.alexpfx.udacity.nanodegree.android.baking_app.step.master.di.ViewModelModule.getStepListFragment() 
    at:  com.github.alexpfx.udacity.nanodegree.android.baking_app.step.master.steps.StepListFragment is injected at 
    com.github.alexpfx.udacity.nanodegree.android.baking_app.step.master.di.ViewModelModule.ingredientsViewModel(stepListFragment, …) 
    com.github.alexpfx.udacity.nanodegree.android.baking_app.step.master.ingredients.IngredientsViewModel is injected at 
    com.github.alexpfx.udacity.nanodegree.android.baking_app.step.master.steps.StepListFragment.ingredientsViewModel 
    com.github.alexpfx.udacity.nanodegree.android.baking_app.step.master.steps.StepListFragment is injected at 
    com.github.alexpfx.udacity.nanodegree.android.baking_app.step.master.di.StepListComponent.inject(stepListFragment) 

La question est: Est-il un moyen de résoudre ce problème en garder la configuration en utilisant le même module, ou devrais-je séparer chaque @Provides dans son module respectif? Est-ce une bonne pratique?

Répondre

1

Les fragments ne doivent pas être des dépendances pour votre ViewModel - le ViewModel est supposé avoir une portée plus grande que celle du fragment.

S'il vous plaît voir this GitHub repo avec un exemple de projet qui utilise des composants d'architecture Android avec Dagger 2.

+0

Mes fragments et activités sont des cibles d'injection, mais je dois leur fournir pour initialiser des objets qui en ont besoin dans les modules. C'est le cas de ViewModels. Que les fragments sont fournis uniquement en interne dans les modules ... – alexpfx

+0

@alexpfx jetez un oeil à [cette réponse] (https://stackoverflow.com/q/44270577/5241933) et en particulier le lien vers le [projet GitHub exemple] (https://github.com/googlesamples/android-architecture-components) –

+0

Bel exemple. Je l'étudierai plus tard. – alexpfx