Dagger2: So verwenden Sie @Provides und @Binds im selben Modul

Lesezeit: 4 Minuten

Ich verwende den neuen Dagger2 (Version 2.11) und nutze die neuen Funktionen wie AndroidInjectorUnd ContributesAndroidInjector. Ich habe eine Aktivitätsunterkomponente,

        @Module
        abstract class ActivityBuilderModule {
            @ContributesAndroidInjector(modules = 
                   {UserListModule.class, MainFragmentModule.class})
            @ActivityScope
            abstract MainActivity bindsMainActivity();

        }



  @Module
  public abstract class MainFragmentModule {
    @ContributesAndroidInjector
    @FragmentScope
    @FragmentKey(UserListFragment.class)
    abstract UserListFragment bindsUserListFragment();

}

Und das UserListModule stellt Abhängigkeiten für das Fragment bereit. Bei einigen Abhängigkeiten möchte ich nur die Instanzen binden und zurückgeben, z

 @Binds
 @ActivityScope
 abstract UserListView mUserListView(UserListFragment userListFragment);

Anstatt einfach nur die Abhängigkeit zurückzugeben, z

@Provides
@ActivityScope
UserListView mUserListView(UserListFragment userListFragment){
    return userListFragment;
}

Mein Modul enthält einige @Provides auch Methoden. Können wir beides nutzen? @Binds Und @Provides Methoden im selben Modul? Ich habe es wie unten gezeigt versucht

        @Module
        public abstract class UserListModule {
            @Provides
            @ActivityScope
            UserListFragment mUserListFragment() {
                return new UserListFragment();
            }

            @Binds
            @ActivityScope
            abstract UserListView mUserListView(UserListFragment userListFragment);

           // other provides and binds methods...
           ......
           .....

        }

Und es ist ein Wurffehler

Error:(22, 8) error: dagger.internal.codegen.ComponentProcessor was unable to process this interface because not all of its dependencies could be resolved. Check for compilation errors or a circular dependency with generated code.

Gibt es eine Möglichkeit, dies zu tun?

  • Ihnen ist doch klar, dass Fragmente, die Sie dem Fragmentmanager hinzufügen, vom System neu erstellt werden und sich nach dem Prozessabbruch wahrscheinlich nicht mehr im Modul befinden, oder?

    – EpicPandaForce

    7. Oktober 2017 um 9:47 Uhr

  • Du meintest, ich solle das Fragment nicht untersuchen? Könnten Sie das bitte klarer formulieren? Ich habe dich nicht richtig verstanden

    Benutzer4260260

    7. Okt. 2017 um 9:51

  • Nach einem Prozesstod wird das Fragment vom System und nicht von diesem Modul initialisiert. Sie werden also wahrscheinlich zwei Instanzen davon haben.

    – EpicPandaForce

    7. Okt. 2017 um 9:58

  • Okay, aber was ist mit der eigentlichen Frage? Können wir sowohl die Binds- als auch die Provides-Methode im selben Modul verwenden?

    Benutzer4260260

    7. Okt. 2017 um 10:06

  • Ich finde @Binds + @Provides sollte funktionieren, aber ich weiß nicht wie ContributesAndroidInjector beeinflusst es.

    – EpicPandaForce

    7. Okt. 2017 um 10:08

@Binds Und @ContributesAndroidInjector Methoden müssen abstrakt sein, da sie keine Methodenkörper haben. Das bedeutet, dass sie sich auf einer Schnittstelle oder einer abstrakten Klasse befinden müssen. @Provides Methoden können sein staticwas bedeutet, dass sie auf abstrakten Klassen und Java-8-kompilierten Schnittstellen basieren können, jedoch nicht statisch („Instanz“) @Provides Methoden funktionieren nicht für abstrakte Klassen. Dies ist in den Dagger-FAQ unter den Abschnitten explizit aufgeführt „Warum nicht? @Binds und Instanz @Provides Methoden gehen in dasselbe Modul?“ Und „Was mache ich stattdessen?“.

Wenn dein @Provides Da die Methode keinen Instanzstatus verwendet, können Sie sie markieren staticund es kann in eine abstrakte Klasse neben Ihrer gehen @Binds Methoden. Wenn nicht, erwägen Sie, die Bindungen wie folgt anzubringen @Binds Und @ContributesAndroidInjector in eine separate Klasse – möglicherweise eine statisch verschachtelte Klasse – und diese mithilfe von einschließen includes Attribut auf Dagger’s @Module Anmerkung.

Eine kleine Ergänzung zu Jeffs obiger Lösung:

Sie können eine innere Schnittstelle anstelle einer statischen inneren Klasse erstellen, wie folgt:

@Module(includes = AppModule.BindsModule.class)
public class AppModule {
    // usual non-static @Provides
    @Provides
    @Singleton
    Checkout provideCheckout(Billing billing, Products products) {
        return Checkout.forApplication(billing, products);
    }
    // interface with @Binds
    @Module
    public interface BindsModule {
        @Binds
        ISettings bindSettings(Settings settings);
    }
}

  • Gibt es neben dem Entfernen des Schlüsselwort-Boilerplates „abstrakt“ einen Vor-/Nachteil bei der Verwendung einer Schnittstelle anstelle einer abstrakten Klasse?

    – Paul T.

    6. Juni 2019 um 9:05 Uhr

  • Gibt es neben dem Entfernen des Schlüsselwort-Boilerplates „abstrakt“ einen Vor-/Nachteil bei der Verwendung einer Schnittstelle anstelle einer abstrakten Klasse?

    – Paul T.

    6. Juni 2019 um 9:07 Uhr

Benutzeravatar von Levon Petrosyan
Levon Petrosyan

In Kotlin können Sie nutzen Begleitobjekt

@Module
interface MyDaggerModule {

    @Binds
    fun provideSomething(somethingImpl: SomethingImpl): Something

    companion object {

        @Provides
        fun provideAnotherThing(): AnotherThing {
            return AnotherThing()
        }
    }
}

  • Es funktioniert nicht mit Multi-Bindung?

    – Bitweise DEVS

    21. Februar 2022 um 16:44

Benutzeravatar von jamescodingnow
jamescodingnow

Dies ist eine Lösung anderer Art: Fügen Sie Module zu anderen Modulen hinzu, danach können Sie das Top-Modul in Ihrer Komponentenschnittstelle aufrufen. Es kann effizienter sein, weil Sie abstrakte und statische Methoden verwenden können.

Details und Beispiele finden Sie unten:

Wir haben zum Beispiel eine Komponentenschnittstelle und zwei Module wie Komponentenklassen, Module_ClassA Und Module_ClassB.

Module_ClassA Ist:

@Module
public class Module_ClassA {

   @Provides
   static ClassA provideClassA(){

     return new ClassA();
   }
}

Module_ClassB Ist:

@Module
abstract class Module_ClassB {

   @Binds
   abstract ClassB bindClassB(Fragment fragment); //Example parameter
}

Jetzt haben wir also zwei Modelle. Wenn Sie sie zusammen verwenden möchten, können Sie sie miteinander kombinieren. Zum Beispiel: Sie können hinzufügen Module_ClassB Zu Module_ClassA:

@Module(includes = Module_ClassB.class)
public class Module_ClassA {

   @Provides
   static ClassA provideClassA(){

     return new ClassA();
   }
}

Schließlich müssen Sie nicht beide Module zu Ihrer Komponentenklasse hinzufügen. Sie können Ihr oberstes Modul nur wie folgt zu Ihrer Komponentenklasse hinzufügen:

Komponentenklassen Ist:

@Component(modules = Module_ClassA)
public interface ComponentClasses {

   //Example code 
   ArrayList<CustomModel> getList();

}

Sie sollten jedoch vorsichtig sein, da Sie Ihr Top-Modul hinzufügen müssen. Daher wurde Module_ClassA zur ComponentClasses-Schnittstelle hinzugefügt.

Jetzt können Sie es wie folgt tun, um die Provides und Binds an derselben Stelle zu haben:

@Module
@InstallIn(ActivityRetainedComponent::class)
internal abstract class YourModule {

  @ActivityRetainedScoped
  @Binds
  abstract fun bindRepository(
    Repository: RepositoryImpl
  ) : Repository

  companion object {
    @Provides
    fun provideApi(
      params: Param
    ) : Api {
      val retrofit = interactorFactory
        .newInteractor<Unit, Unit>()
        .interaction()
        .buildRetrofitClient()
      return retrofit.create(Api::class)
    }
  }

}

1452390cookie-checkDagger2: So verwenden Sie @Provides und @Binds im selben Modul

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy