Один объект, если внедрен в 2 подкомпонента в той же пользовательской области, каждый раз, когда создается новый экземпляр этого объекта

Один объект, если его внедрить в 2 подкомпонента в одной и той же пользовательской области, каждый раз, когда создается новый экземпляр этого объекта. Я хочу, чтобы один и тот же экземпляр передавался всем подкомпонентам

это модуль

@CustomScope
@Module
public class EventBusModule {

    PublishSubject<Boolean> bus = PublishSubject.create();

    @CustomScope
    @Provides
    public PublishSubject<Boolean> provideRxBus() {
        return bus;
    }
}

это мои подкомпоненты

@Module
public abstract class ActivityBindingModule {

    @CustomScope
    @ContributesAndroidInjector(modules = {HomeActivityModule.class, 
    EwayBillFragmentProvider.class, EventBusModule.class})
    abstract HomeActivity mainActivity();

    @CustomScope
    @ContributesAndroidInjector(modules = 
    {EwayBillDetailActivityModule.class, EventBusModule.class})
    abstract EwayBillDetailActivity ewayBillDetailActivity();
}

Эти подкомпоненты написаны внутри ActivityBindingModule, который добавлен в мой компонент приложения. Теперь мне нужен один и тот же экземпляр моего объекта PublishSubject в обоих подкомпонентах, я новичок в кинжале и хочу знать, что я делаю не так?

1 ответ

Решение

Вам нужно будет переместить bus в область применения, что обычно означает аннотирование @Singleton (если вы так аннотировали свой компонент верхнего уровня, в который установлен ActivityBindingModule). Вам также нужно будет переместить ваш метод в модуль, установленный на этом компоненте, который также может быть ActivityBindingModule.

@Module
public abstract class ActivityBindingModule {

  @Singleton
  @Provides
  public PublishSubject<Boolean> provideRxBus() {
    // Dagger stores the instance in your Application component, so you don't have to.
    return PublishSubject.create();
  }

  /* ... your @ContributesAndroidInjector Activity bindings remain here ... */
}

Сначала объяснение того, что вы видите: @ContributesAndroidInjector создает подкомпонент для каждого аннотируемого объекта, помеченный аннотациями области действия и модулями, которые вы надеваете @ContributesAndroidInjector метод и аннотации, так что ваш вызов AndroidInjection.inject(this) в onCreate создает новый экземпляр этого подкомпонента и использует его для внедрения экземпляра Activity.

Ваш @CustomScope (который может быть лучше назван как @ActivityScope здесь) на @Provides PublishSubject<Boolean> Метод означает, что ваш экземпляр будет использовать тот же жизненный цикл, что и компонент, также аннотированный этой аннотацией области действия. Здесь каждый автоматически генерируемый подкомпонент. Кроме того, поскольку ваш модуль является неабстрактным классом с открытым конструктором без аргументов, Dagger автоматически создает новый экземпляр каждый раз, когда создает компонент, для которого требуется ваш модуль, что означает bus для каждого экземпляра Activity. (Это не может и не будет делать это для модулей, которые являются абстрактными классами или интерфейсами.)


Вы хотите, чтобы ваш bus объект должен быть одним и тем же экземпляром между действиями, что означает, что @CustomScope / @ActivityScope слишком короток: вы хотите, чтобы объект пережил жизненный цикл любого отдельного действия. Это означает, что вам нужно либо сохранить экземпляр в другом месте и передать его в каждое действие, либо вам необходимо сохранить экземпляр в самом компоненте приложения. Я бы порекомендовал последнее, потому что это одна из проблем, которые Dagger был создан для решения, и потому что это автоматически сделает шину доступной для вашего приложения: подкомпоненты Dagger наследуют доступ ко всем привязкам в своих родительских компонентах. Это дает код, который вы видите выше. (Обратите внимание, что, выполнив это, вы сохраните экземпляр PublishSubject даже в том случае, если не будет отображаться действие, когда ваше приложение работает в фоновом режиме; если вы хотите, чтобы один и тот же экземпляр был между действиями, это необходимое следствие, но выберите это тщательно, чтобы избежать слишком большого использования фоновой памяти.)

Одним из вариантов является то, что вы отслеживаете bus например, и вставьте его в каждое действие. Вы можете сделать это, если ваш модуль получит параметр, но это довольно сложно сделать с dagger.android (который @ContributesAndroidInjector). Вы также можете написать @Provides метод, который делегирует WeakReference, или использовать @Singleton Техника выше, чтобы написать держатель, который временно хранит ваши bus между мероприятиями. Однако, поскольку Android в значительной степени контролирует ваши переходы между операциями и жизненным циклом активности, возможно, лучше всего сохранить bus в @Singleton сфера, как я сделал в коде выше.

Другие вопросы по тегам