web-dev-qa-db-fra.com

Dague 2 Portée personnalisée pour chaque fragment (ou activité, etc.)

J'ai regardé quelques articles différents qui semblent suggérer deux façons différentes de faire un cadrage personnalisé dans Dagger 2:

  1. Présentateurs MVP qui survivent aux changements de configuration, partie 2 ( Repo Github ):

    • Utilise des étendues personnalisées uniques pour chaque fragment, par exemple @Hello1Scope et @Hello2Scope pour Hello1Fragment et Hello2Fragment respectivement
  2. Dasting Dagger 2 sur Android :

    • Utilise une seule étendue personnalisée pour tous les fragments, par exemple @PerFragment.

D'après ce que je comprends, il semble que, comme dans la méthode 2, il devrait être correct d'avoir une seule portée définie qui peut être utilisée pour tous les fragments (c'est-à-dire @PerFragment). En fait (veuillez me corriger si je me trompe), il semble que le nom de l'étendue personnalisée ne soit pas pertinent, et ce n'est que là où le sous-composant est créé (c'est-à-dire dans Application, Activité ou Fragment) qui compte.

Existe-t-il un cas d'utilisation pour définir une portée unique pour chaque fragment, comme dans le cas 1?

35
bcorso

Après avoir lu la réponse de @vaughandroid, et Qu'est-ce qui détermine le cycle de vie d'un composant (graphique d'objet) dans Dagger 2? Je pense que je comprends assez bien les étendues personnalisées pour répondre à ma propre question.

Tout d'abord, voici quelques règles concernant les composants, les modules et les annotations de portée dans dagger2.

  • Un composant doit possède une annotation de portée (unique) (par exemple @Singleton ou @CustomScope).
  • Un module pas possède une annotation de portée.
  • A Méthode du module peut-être une (seule) portée qui correspond à son composant ou aucune portée, où:
    • Portée : signifie qu'une seule instance est créée pour chaque instance du composant.
    • Unscoped : signifie qu'une nouvelle instance est créée avec chaque appel inject () ou fournisseur
    • REMARQUE: Dagger2 réserves @Singleton pour le composant racine (et ses modules) uniquement. Les sous-composants doivent utiliser une étendue personnalisée, mais la fonctionnalité de cette étendue est exactement la même que @Singleton.

Maintenant, pour répondre à la question: je dirais créer une nouvelle étendue nommée pour chaque étendue conceptuellement différente. Par exemple, créez un @PerActivity, @PerFragment, ou @PerView annotation qui indique où le composant doit être instancié, et indique ainsi sa durée de vie.

Remarque : il s'agit d'un compromis entre deux extrêmes. Considérons le cas d'un composant racine et des sous-composants n dont vous aurez besoin:

  • au moins 2 annotations (@Singleton et @SubSingleton), et
  • tout au plus n + 1 annotations (@Singleton, @SubSingleton1, ... @SubSingletonN).

Exemple:

Application:

/** AppComponent.Java **/ 
@Singleton
@Component( modules = AppModule.class )
public interface AppComponent{
    void inject(MainActivity mainActivity);
}

/** AppModule.Java **/
@Module
public class AppModule{
    private App app;

    public AppModule(App app){
        this.app = app;
    }

    // For singleton objects, annotate with same scope as component, i.e. @Singleton
    @Provides @Singleton public App provideApp() { return app; }
    @Provides @Singleton public EventBus provideBus() { return EventBus.getDefault(); }
}

Fragment:

/** Fragment1Component.Java **/
@PerFragment
@Component( modules = {Fragment1Module.class}, dependencies = {AppComponent.class} )
public interface Fragment1Component {
    void inject(Fragment1 fragment1);
}

/** Fragment1Module.Java **/ 
@Module
public class Fragment1Module {
    // For singleton objects, annotate with same scope as component, i.e. @PerFragment
    @Provides @PerFragment public Fragment1Presenter providePresenter(){
        return new Fragment1Presenter();
    }
}

/** PerFragment.Java **/ 
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerFragment {}
79
bcorso

Votre compréhension est correcte. Les étendues nommées vous permettent de communiquer votre intention, mais elles fonctionnent toutes de la même manière.

  • Pour les méthodes de fournisseur étendues, chaque instance de composant crée 1 instance de l'objet fourni.
  • Pour les méthodes de fournisseur non étendues, chaque instance de composant crée une nouvelle instance de l'objet fourni chaque fois qu'elle a besoin de l'injecter.

La durée de vie de l'instance Component est cependant importante. 2 instances différentes du même composant fourniront des instances d'objets différentes, même de portée.

Les noms d'étendue doivent indiquer la durée de vie de l'objet fourni (qui correspond à celle de l'instance Component) donc @PerFragment est beaucoup plus logique pour moi.

D'un rapide coup d'œil au didacticiel "MVP Presenters ...", il n'est pas clair pour moi quelle est exactement l'intention de l'auteur d'avoir des portées distinctes. Puisque les noms sont juste jetables, je ne lirais pas trop dedans.

17
vaughandroid