web-dev-qa-db-fra.com

Quel est le cas d'utilisation de l'annotation @Binds vs @Provides dans Dagger2

Je ne suis pas certain du but de Dagger2 @ Bind annotation.

D'après ce que j'ai lu en ligne, je ne suis toujours pas clair, mais voici un exemple:

@Module
public abstract class HomeModule {

  @Binds
  public abstract HomePresenter bindHomePresenter(HomePresenterImp   
    homePresenterImp);
}

et les définitions de classe ressemblent à ceci:

public interface HomePresenter {
    Observable<List<User>> loadUsers();
}

public class HomePresenterImp implements HomePresenter {

    public HomePresenterImp(){
    }  

    @Override
    public Observable<List<User>> loadUsers(){
        //Return user list observable
    }
}

pourquoi aurais-je besoin d'utiliser @Binds si je peux simplement utiliser fournit une annotation comme suit:

@Provides
public HomePresenter provideHomePresenter() {
    return new HomePresenterImp();
}

quel est le cas d'utilisation de @Binds au lieu de @Provides? si j'utilise @Binds, dois-je encore le déclarer dans mon composant d'application (c'est une classe abstraite lorsque j'utilise @Binds)?

14
j2emanue

@Binds peut être parfaitement équivalent à une méthode annotée @ Provides comme celle-ci:

@Provides
public HomePresenter provideHomePresenter() {
    return new HomePresenterImp();
}

... bien que vous préfériez probablement une variante qui prend HomePresenterImp comme paramètre de méthode, ce qui permet à Dagger d'instancier HomePresenterImp (en supposant qu'il possède un constructeur @Inject), y compris en passant toutes les dépendances dont il a besoin. Vous pouvez également faire ceci static, donc Dagger n'a pas besoin d'instancier votre instance de Module pour l'appeler.

@Provides
public static HomePresenter provideHomePresenter(HomePresenterImp presenter) {
    return presenter;
}

Alors pourquoi choisiriez-vous @Binds au lieu? Dagger a un FAQ à ce sujet , mais il se résume à ces raisons:

  • @Binds est (légèrement) plus compact: vous pouvez ignorer l'implémentation.
  • @Binds fonctionne dans les interfaces et les classes abstraites, qui sont strictement requises pour les fonctionnalités Dagger comme @BindsOptionalOf et @ContributesAndroidInjector.
  • @Binds aide votre code à rester efficace. Les méthodes @Provides peuvent être des méthodes d'instance, qui nécessitent que Dagger instancie votre module pour les appeler. Faire votre méthode @Provides static accomplira également cela, mais votre méthode @Provides sera toujours compilée si vous oubliez le static. Les méthodes @Binds ne le seront pas.
  • @Binds empêche Dagger d'avoir à coder et conserver un Factory/Provider séparé pour l'objet, car Java ne donne pas accès à Dagger pour savoir que l'implémentation est aussi simple qu'elle l'est. Dans votre cas, Dagger peut lancer le Provider<HomePresenterImp> à un Provider<HomePresenter> et n'en conserver qu'un, plutôt que d'en conserver un pour HomePresenter qui ne fait rien d'autre que d'appeler celui de HomePresenterImp.

Ainsi, le tout serait bien représenté comme:

@Binds abstract HomePresenter bindHomePresenter(HomePresenterImp presenter);

Voici un cas concret où vous avez besoin d'une annotation Bind, imaginez que vous avez un BaseActivityModule qui est inclus dans tous vos modules d'activité et qui fournit votre modèle de vue d'activité.

@Module
object BaseActivityModule {
    @Provides
    @ActivityScope
    @ActivityContext
    @JvmStatic
    fun provideViewModelProvider(
        activity: AppCompatActivity,
        viewModelFactory: ViewModelProvider.Factory
    ): ViewModelProvider = ViewModelProviders.of(activity, viewModelFactory)
}

Ici, vous voyez, nous devons fournir un AppCompatActivity et un ViewModelProvider.Factory. Vous ne pouvez pas fournir à AppCompatActivity une annotation Provide car les activités sont créées par Android.

Nous supposons que votre béton ActivityModule par exemple MainActivityModule fournira la classe MainActivity soit parce que vous créez un sous-composant MainActivity soit parce que vous avez utilisé ContributesAndroidInjector pour créer automatiquement votre sous-composants (mais ceci est un autre discours).

Nous avons donc notre MainActivityModule fournissant MainActivity et notre MainActivityModule inclut notre BaseActivityModule qui a besoin d'un AppCompatActivity. Voici donc la magie de Bind, disons à Dagger que lorsque vous avez besoin d'un AppCompatActivity, vous pouvez utiliser notre MainActivity.

@Module(includes = [BaseActivityModule::class])
abstract class MainActivityModule {
    @Binds
    @ActivityScope
    abstract fun bindActivity(activity: MainActivity): AppCompatActivity
}

Vous pouvez voir plus de mon modèle de projet ici

2
Samuel Eminet