Инъекция Dagger 2 в класс Java без активности

Я пытаюсь использовать Dagger2 для DI, он отлично работает для классов, связанных с Activity/Fragment, где есть событие жизненного цикла onCreate. Теперь у меня есть простой класс Java, который я хочу внедрить. Любые идеи относительно того, как это сделать, будут оценены. Код у меня выглядит так:

BasicMoviesUsecaseComponent.java —

@PerActivity
@Component(dependencies = AppComponent.class, modules = BasicMoviesUsecasesModule.class)
public interface BasicMoviesUsecasesComponent {
    void inject(PaymentsManager paymentsManager);
}

DatabaseModule.java —

    @Module
    public class DatabaseModule {
       @Provides @Singleton
       Realm provideRealmInstance(Context context) {

           return Realm.getInstance(context);
       }

       @Provides @Singleton
       DatabaseProvider provideDatabaseInstance(Realm realm) {

           return new DatabaseProvider(realm);
       }

       @Provides @Singleton
       SharedPreferences provideSharedPrefs(Context context) {

            return context.getSharedPreferences(context.getPackageName()+"_prefs", Context.MODE_PRIVATE);
       }

       @Provides @Singleton
       SharedPreferencesManager provideSharedPreferencesManager(SharedPreferences sharedPreferences) {
            return new SharedPreferencesManager(sharedPreferences);
       }

        @Provides @Singleton
        PaymentsManager providePaymentsManager(SharedPreferencesManager sharedPreferencesManager) {

              return new PaymentsManager(sharedPreferencesManager);

        }

}

AppComponent.java —

  @Singleton
  @Component(modules = {
    ApplicationModule.class,
    DomainModule.class,
    DatabaseModule.class
   })

public interface AppComponent {

    Bus bus();
    Realm realm();
    DatabaseProvider dbProvider();
    SharedPreferencesManager sharedPreferencesManager();
}

Вот класс, в который мне нужно внедрить SharedPreferencesManager, и я не могу этого сделать:

MyManager.java -

 private class MyManager {
    private SharedPreferencesManager manager;

    @Inject
    MyManager(SharedPreferencesManager manager){
          this.manager = manager;           
    } 

    private void initializeDependencyInjector() {

          BMSApplication app = BMSApplication.getInstance();

          DaggerBasicMoviesUsecasesComponent.builder()
                 .appComponent(app.getAppComponent())
                 .basicMoviesUsecasesModule(new BasicMoviesUsecasesModule())
                 .build().inject(PaymentsManager.this);
    }

}

Как вызвать initializeDependencyInjector()?


person Adnan Mulla    schedule 24.02.2016    source источник


Ответы (2)


Как правило, вы должны использовать внедрение конструктора, когда это возможно. Вызов component.inject(myObject) в основном используется для объектов, которые вы не можете создавать самостоятельно (например, действия или фрагменты).

Внедрение конструктора — это то, что вы уже сделали:

private class MyManager {
    private SharedPreferencesManager manager;

    @Inject
    MyManager(SharedPreferencesManager manager){
          this.manager = manager;           
    } 
}

Dagger создаст объект для вас и передаст ваш SharedPreferencesManager. Нет необходимости вызывать init или что-то подобное.

Настоящий вопрос заключается в том, как получить объект MyManager. Чтобы сделать это, опять же, кинжал справится с этим за вас.

Аннотируя конструктор с помощью @Inject, вы сообщаете dagger, как он может создать объект этого типа. Чтобы использовать его, просто введите его или объявите как зависимость.

private class MyActivity extends Activity {
    @Inject
    MyManager manager;

    public void onCreate(Bundle savedState){
        component.inject(this);  
    } 
}

Или просто добавьте геттер к компоненту (пока SharedPreferenceManager может быть предоставлено, MyManager также может быть создан):

@Component(dependencies = SharedPreferenceManagerProvidingComponent.class)
public interface MyComponent {

    MyManager getMyManager();
}
person David Medenjak    schedule 25.02.2016
comment
Как эта зависимость будет выполняться SharedPreferencesManager manager? - person eC Droid; 19.07.2017
comment
@eCDroid Вам необходимо убедиться, что он может быть либо внедрен и создан конструктором, либо модуль предоставляет его, либо он привязан к компоненту, либо его может предоставить родительская зависимость или зависимость компонента. На самом деле вам решать, как вы хотите предоставить зависимость, компонент просто должен иметь к ней доступ. - person David Medenjak; 19.07.2017
comment
Обеспечивает ли это в вашем случае dependencies = SharedPreferenceManagerProvidingComponent.class? Также, пожалуйста, объясните этот тег - person eC Droid; 19.07.2017
comment
что, если вы не хотите, чтобы MyManager не создавался кинжалом, и вам нужно создать его самостоятельно, например, ViewAdapter для recyclerview? - person Jonathan; 13.02.2018
comment
@jonney, тогда вы просто вставите то, что вам нужно, в родительскую активность/фрагмент, а затем, я думаю, передадите это в конструктор ViewAdapter. Поправьте меня если я ошибаюсь. - person nilsi; 02.01.2019
comment
Как передать экземпляр активности его зависимостям? - person K Pradeep Kumar Reddy; 29.09.2020

Я тоже сталкиваюсь с этой проблемой. У меня есть MailgunService, который я использую в одном из моих валидаторов текстового поля. Этот валидатор сделан таким образом, что я могу определить его в макете XML как app:rule="mailgun|email".

Итак, в основном я получаю доступ к валидатору внутри реализации пользовательского представления, этому валидатору требуется обслуживание, и я хочу использовать кинжал, чтобы не создавать весь этот httpclient, модификации и т. д. Что является адом зависимостей, если создается вручную.

Поэтому я нашел такой способ сделать это.

Сначала внутри вашего AppComponent вы делаете:

interface  AppComponent { 
    ...
    // getters
    fun getMailgunService(): IMailgunService
}

Затем в приложении вы делаете

 companion object { lateinit var INSTANCE: MyApp }

Затем внутри вашего класса, где вы хотите внедрить службу IMailgun из кинжала AppComponent, вы можете сделать

private var service: IMailgunService

 init {
        val component = DaggerAppComponent
            .builder()
            .application(CRMApp.INSTANCE)
            .build()

        service = component.getMailgunService()
    }

И он вводится, и он работает!

person Michał Ziobro    schedule 11.05.2020