2017-10-14 12 views
0

J'ai une MainActivity qui injecte Presenter, un objet presenter injecte interacteur et un objet interacteur injecte APIHelper. Tous les fournisseurs de présentateur, interacteur et APIHelper sont là dans MainModule.Dagger2 ne résolvant pas complètement la dépendance

@Module 
public class MainActivityModule { 
private final MainActivity activity; 
//Context context; 

public MainActivityModule (MainActivity activity) { 
    this.activity = activity; 
} 



@Provides 
@Singleton 
public MainViewPresenter providesMainPresenter(){ 
    return new MainPresenterImpl(activity); 
} 

@Provides 
@Singleton 
ListingInteractor providesInteractor(){ 
    return new ListingInteractorImpl(activity); 
} 

@Provides 
@Singleton 
ApiHelper providesAPI(){ 
    return new ApiHelper(activity); 
} 

} 

J'ai injecté le composant dans le MainActivity comme:

DaggerMainActivityComponent.builder() 
       .mainActivityModule(new MainActivityModule(MainActivity.this)) 
       .build().inject(this); 

Dans ma mise en œuvre Présentateur Je interacteur comme:

public class MainPresenterImpl implements MainViewPresenter { 
     Context context; 
    private MainView mainView; 
    // @Inject 
    ListingInteractor interactor; //here i get null interactor 
    MyScrollListener scrollListener; 

    public MainPresenterImpl(MainActivity activity) { 

     this.context = activity; 
     this.mainView = activity; 
    } 
    @Override 
    public void getCatFacts() { 
     interactor.getFacts(); 
    } 

Ma interacteur classe d'implémentation a helper API dont les besoins constructeur contexte

public class ListingInteractorImpl implements ListingInteractor{ 
    private Context context; 
    @Inject 
    private APIHelper; // getting null APIHelper 



    public ListingInteractorImpl(Context context) { 
     this.context = context; 

    } 

Mon interface composant est comme:

@Component(modules={MainActivityModule.class}) 
@Singleton 
public interface MainActivityComponent { 



    void inject(MainActivity mainActivity); 

    /*void inject(MainPresenterImpl presenter);*/ 



    MainViewPresenter getMainPresenter(); 

    ListingInteractor getInteractor(); 

    ApiHelper getHelper(); 
} 

mais seul objet présentateur est créé dans le MainActivity tous les autres objets, y compris le présentateur interacteur, apihelper sont null.According à Dagger il faut résoudre toutes les dépendances.

+0

Injectez-vous le présentateur dans votre composant Dagger? Sinon, je ne pense pas que ça va marcher. Généralement, l'activité a un @Inject Presenter p; et le présentateur a l'itérateur ou tout ce que vous voulez lui injecter, injecté dans son constructeur. Le constructeur du présentateur sera donc MainPresenterImpl (activité, itérateur). Et Dagger saura quoi injecter avez-vous fourni l'itérateur dans le module (donno si c'est clair) – Eselfar

+0

Il semble qu'il vous manque quelques bases sur l'utilisation de Dagger et comment cela fonctionne. Je vous recommande de lire à nouveau le Dagger 2 Users Guide, ou d'autres didacticiels, et de vous assurer que vous comprenez comment approvisionner ou injecter des dépendances. –

+0

@Eselfar J'ai ajouté du code pour l'interface du composant. J'ai présentateur dans le composant et il est initialisé dans MainActivity mais les objets que j'injecte dans le présentateur ne sont pas initialisés comme l'interacteur et l'apihelper dedans interacteur – ozmank

Répondre

0

Dagger est pas magique. Il n'insèrera pas d'objets magiquement où vous voulez à moins que vous ne le disiez.

public class MainPresenterImpl implements MainViewPresenter { 
    // ... other fields ... 
    @Inject 
    ListingInteractor interactor; 

    public MainPresenterImpl(MainActivity activity) { 
    this.context = activity; 
    this.mainView = activity; 
    } 
} 

Pour Dagger c'est rien ... rien. Vous avez marqué un certain champ (ListingInteractor) pour l'injection de champ, mais à moins que vous appeliez manuellement un composant pour injecter votre objet, rien ne se passera. L'injection de champ doit être réservée pour les activités et les fragments où vous ne pouvez pas ajouter d'arguments au constructeur, pas pour vos classes moyennes.

@Provides 
@Singleton 
MainViewPresenter providesMainPresenter(){ 
    return new MainPresenterImpl(activity); 
} 

Au lieu de laisser Dagger créer MainPresenterImpl pour vous, vous faites un appel à vous, passer seulement dans l'activité. Comme il n'y a pas d'appel à MainPresenterImpl.interactor, ce sera null. Vous n'utilisez pas l'injection de champ, vous appelez le constructeur vous-même et vous n'attribuez pas le champ.
La création manuelle d'objets dans les modules doit être réservée aux objets nécessitant une configuration supplémentaire, tels que Retrofit ou OkHttp avec leurs générateurs. Si vous voulez que vos champs soient définis, vous pouvez utiliser l'injection de champ et enregistrer vos objets avec le composant (ces méthodes inject(FieldInjectableClass clazz)) et saupoudrer component.inject(myObject) dans tout votre code, ce qui serait une très mauvaise idée car vous finiriez par écrire beaucoup de passe-partout dont vous n'avez pas besoin.

Le moyen le plus raisonnable est de déplacer vos dépendances vers le constructeur, où elles appartiennent.

public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) { /* ... */ } 

Si vous avez une dépendance sur une autre classe, pourquoi ne pas la déclarer comme telle? Mais cela laisse toujours le plat de vous créer l'objet vous-même, au lieu de laisser Dagger faire son travail.

C'est pourquoi vous devez utiliser Injection de constructeur. Comme son nom l'indique, il s'agit du constructeur. Il suffit d'ajouter l'annotation @Inject:

@Inject // marked for constructor injection! 
public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) { /* ... */ } 

maintenant Dague sait sur ce point d'entrée à votre classe et peut créer.

Pour laisser dague gérer les choses que vous pouvez ajouter le champ @Singleton à la classe elle-même (annoter la classe, pas le constructeur) et simplement supprimer la méthode @Provides pour elle (il n'y a pas besoin de fournit des méthodes de modules pour les objets qui don Vous n'avez pas besoin de configuration supplémentaire), mais comme vous liez une implémentation à une interface, vous devez toujours spécifier la classe que vous voulez lier à l'interface.

@Provides 
@Singleton 
MainViewPresenter providesMainPresenter(MainPresenterImpl implementation){ 
    return implementation; 
} 

Depuis Dagger peut créer MainPresenterImpl avec l'injection de constructeur, vous pouvez retourner l'implémentation de l'interface, et il n'y a pas besoin de mettre à jour le code dans le cas où les changements de signature du constructeur, comme dague simplement adapter l'instanciation de classe en conséquence.

Comment utiliser l'injection de constructeur et lier les implémentations aux interfaces. Et comme mentionné, je recommande fortement de lire sur les bases. Assurez-vous de comprendre ce que fait Dagger et comment cela fonctionne. Soyez sûr de connaître la différence entre l'injection de champ et de constructeur, ou quand utiliser des modules.

Le temps que vous investissez maintenant dans l'apprentissage de Dagger signifie beaucoup moins de débogage et d'erreurs plus tard.


Dans le cas où votre module est abstraite ou une interface, vous pouvez également utiliser la méthode @Binds, où dague simplement générer le code ci-dessus passe-partout.

@Binds 
@Singleton 
MainViewPresenter providesMainPresenter(MainPresenterImpl implementation); 
0

changement MainPresenterImpl & ListingInteractorImpl constructeurs à suivre et les précéder avec @Inject:

 

    @Inject 
    public MainPresenterImpl(MainActivity activity, ListingInteractor interactor) {...} 

    @Inject 
    public ListingInteractorImpl(Context context, APIHelper helper) {...} 
 

Ensuite, dans l'implémentation du module:

 

    @Provides 
    @Singleton 
    public MainViewPresenter providesMainPresenter(ListingInteractor interactor){ 
     return new MainPresenterImpl(activity, interactor); 
    } 

    @Provides 
    @Singleton 
    ListingInteractor providesInteractor(APIHelper helper){ 
     return new ListingInteractorImpl(activity, helper); 
    }