Dagger 2.10 Android подкомпоненты и компоновщики
Используя новые (в 2.10) классы dagger.android, я пытаюсь внедрить вещи, используя подкомпонент, который зависит от других модулей, и, следовательно, имеет Builder с установщиками для этих модулей. Документация на https://google.github.io/dagger/android.html описывает это, но не ясно, как на самом деле писать и / или вызывать эти установщики.
Цитирование по вышеуказанной ссылке:
AndroidInjection.inject () получает DispatchingAndroidInjector из приложения и передает вашу активность для инъекции (Activity). DispatchingAndroidInjector ищет AndroidInjector.Factory для класса вашей активности (которым является YourActivitySubcomponent.Builder), создает AndroidInjector (который является YourActivitySubcomponent) и передает вашу активность для внедрения (YourActivity).
Мне кажется, что для того, чтобы иметь возможность вызывать сеттеры для Билдера, мне нужно где-то туда попасть и убедиться, что у Билдера есть все необходимые данные? Проблема, которую я вижу в том, что во время выполнения я получаю IllegalStateException: MODULE must be set
, когда сгенерированный конструктор для моего субкомпонента вызывается AndroidInjector.
Подкомпонент, о котором идет речь, на самом деле относится к Фрагменту, а не к Деятельности, но я не уверен, что это должно иметь значение. Есть идеи о том, как это сделать?
2 ответа
Короче говоря, вы должны переопределить вызовseedInstance
в Builder (который является абстрактным классом, а не интерфейсом) для предоставления других необходимых вам модулей.
редактировать: прежде чем сделать, проверьте и убедитесь, что вам действительно нужно пройти этот модуль. Как добавил Деймон в отдельном ответе, если вы создаете специальный модуль для своего класса Android, вы можете рассчитывать на автоматическое внедрение этого класса для извлечения конфигурации или экземпляра из графика в этой точке. Подумайте о его подходе, если проще просто исключить параметры конструктора из вашего модуля, что также может обеспечить более высокую производительность, поскольку они позволяют избежать ненужных экземпляров и вызовов виртуальных методов.
Во-первых, dagger.android за 30 секунд: вместо того, чтобы каждая деятельность или фрагмент знали о своем родителе, эта операция (или фрагмент) вызывает AndroidInjection.inject(this)
, который проверяет заявку на HasActivityInjector
(или родительские фрагменты, деятельность и приложение для HasFragmentInjector
). Идея состоит в том, что вы вносите привязку в созданный мульти-привязок Map<Class, AndroidInjector.Factory>
где привязанные привязки - почти всегда компоновщики подкомпонентов, которые вы пишете, которые создают специфичные для объекта подкомпоненты.
Как вы могли бы сказать из AndroidInjection.inject(this)
а также AndroidInjector.Factory.create(T instance)
у вас мало возможностей для передачи деталей, относящихся к конкретным операциям или фрагментам, вашему построителю. Вместо этого идея состоит в том, что ваш субкомпонентный конструктор переопределяет seedInstance
реализация. Как в документах для seedInstance
:
Обеспечивает
instance
для использования в графе привязки построенногоAndroidInjector
, По умолчанию это используется какBindsInstance
метод, но он может быть переопределен для предоставления любых модулей, которые нуждаются в ссылке на действие.Это должен быть тот же экземпляр, который будет передан
inject(Object)
,
Это будет выглядеть примерно так:
@Subcomponent(modules = {OneModule.class, TwoModule.class})
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> {
// inject(YourActivity) is inherited from AndroidInjector<YourActivity>
@Builder
public abstract class Builder extends AndroidInjector.Builder<YourActivity> {
// Here are your required module builders:
abstract Builder oneModule(OneModule module);
abstract Builder twoModule(TwoModule module);
// By overriding seedInstance, you don't let Dagger provide its
// normal @BindsInstance implementation, but you can supply the
// instance to modules or call your own BindsInstance:
@Override public void seedInstance(YourActivity activity) {
oneModule(new OneModule(activity));
twoModule(new TwoModule(activity.getTwoModuleParameter()));
}
}
}
Здесь предполагается, что вам нужно ждать activity
экземпляр для модулей. Если нет, то у вас также есть возможность вызывать их, когда вы связываете субкомпонент:
@Provides @IntoMap @ActivityKey(YourActivity.class)
AndroidInjector.Factory bindInjector(YourActivitySubcomponent.Builder builder) {
return builder
.oneModule(new OneModule(...))
.twoModule(new TwoModule(...));
}
... но если вы можете сделать это, то вам легче было бы позаботиться об этих привязках, переопределив эти модули, реализовав конструктор с нулевым аргументом, который может предоставлять параметры конструктора модуля, и позволяя Dagger создавать их так, как это делается для любого Модули с общедоступными нулевыми конструкторами.
Это работает, но это не нужно. метод seedInstance предоставляет экземпляр активности в граф, так что вы можете иметь MyActivityModule без состояния и просто запрашивать MyActivity в ваших методах @Provides.
class MyActivityModule {
@Provides
static SomethingDerivedFromMyActivity providesMethod(MyActivity myActivity) {
return myActivity.somethingDerived();
}
}
Это сохраняет экземпляр модуля и позволяет сгенерированным фабрикам быть более компактными.