Комментарии 6
Большое спасибо за статью!
Хотел бы кое-что добавить:
1) AndroidInjectionModule нужен для пустых мап. Пустые мапы могут возникнуть когда мы не вставляем никаких сабкомпонентов Activtiy в компонент Application'a, но при этом инджектим в Application инстанс DispatchingAndroidInjector. Если же у нас есть хотя бы один IntoMap то все будет ok. Цитата из документации «You do not have to use @Multibinds for sets or maps that have at least one @IntoSet, @ElementsIntoSet, or @IntoMap binding, but you do have to declare them if they may be empty.».
2) «К примеру активити сабкомпонент создается в момент вызова AndroidInjection.inject() и живет до тех пор пока активити не уничтожена.». Казалось бы это не совсем правда? Если заглянуть в код DispatchingAndroidInjector#maybeInject, то видно что там создается инстанс билдера, а сам он никуда не сохраняется. Но если у нас в активити инджектится DispatchingAndroidInjector (для внедрения фрагментов), то ссылка на сабкомпонент активити замкнется через билдер сабкомпонента фрагмента (так как он является inner классом). В итоге получается что сабкомпоненты самых глубоких сущностей умирают сразу после инджекта.
3) Касательно передачи динамических параметров. 1-й вариант плох тем, что требует контракта, что мы не используем userId, пока не вызван setUserId. 2-й вариант плох тем, что вьюха управляет презентером. 3-й способ наиболее чист, но как верно подмечено, слегка громоздок.
Добавлю еще 2 способа, которые нашел в issues даггера.
a) Инстанс активити или фрагмента, добавляется в граф после вызова AndroidInjection.inject(this), и поэтому все необходимые аргументы можно достать оттуда (то есть активити можно передавать как аргумент в Provides методы модуля и доставать оттуда что нужно).
b) Мы можем добавить BindsInstance методы в билдер, отнаследованный от AndroidInjector.Factory. Далее переопределяем метод seedInstance у билдера, и вызываем все методы BindsInstance, при этом достаем параметры из активити/фрагмента переданного аргументом в seedInstance. Вообще использование BindsInstance более предпочтительно чем конструкторы модуля. Из доков «Binding an instance is equivalent to passing an instance to a module constructor and providing that instance, but is often more efficient. When possible, binding object instances should be preferred to using module instances.»
Хотел бы кое-что добавить:
1) AndroidInjectionModule нужен для пустых мап. Пустые мапы могут возникнуть когда мы не вставляем никаких сабкомпонентов Activtiy в компонент Application'a, но при этом инджектим в Application инстанс DispatchingAndroidInjector. Если же у нас есть хотя бы один IntoMap то все будет ok. Цитата из документации «You do not have to use @Multibinds for sets or maps that have at least one @IntoSet, @ElementsIntoSet, or @IntoMap binding, but you do have to declare them if they may be empty.».
2) «К примеру активити сабкомпонент создается в момент вызова AndroidInjection.inject() и живет до тех пор пока активити не уничтожена.». Казалось бы это не совсем правда? Если заглянуть в код DispatchingAndroidInjector#maybeInject, то видно что там создается инстанс билдера, а сам он никуда не сохраняется. Но если у нас в активити инджектится DispatchingAndroidInjector (для внедрения фрагментов), то ссылка на сабкомпонент активити замкнется через билдер сабкомпонента фрагмента (так как он является inner классом). В итоге получается что сабкомпоненты самых глубоких сущностей умирают сразу после инджекта.
3) Касательно передачи динамических параметров. 1-й вариант плох тем, что требует контракта, что мы не используем userId, пока не вызван setUserId. 2-й вариант плох тем, что вьюха управляет презентером. 3-й способ наиболее чист, но как верно подмечено, слегка громоздок.
Добавлю еще 2 способа, которые нашел в issues даггера.
a) Инстанс активити или фрагмента, добавляется в граф после вызова AndroidInjection.inject(this), и поэтому все необходимые аргументы можно достать оттуда (то есть активити можно передавать как аргумент в Provides методы модуля и доставать оттуда что нужно).
b) Мы можем добавить BindsInstance методы в билдер, отнаследованный от AndroidInjector.Factory. Далее переопределяем метод seedInstance у билдера, и вызываем все методы BindsInstance, при этом достаем параметры из активити/фрагмента переданного аргументом в seedInstance. Вообще использование BindsInstance более предпочтительно чем конструкторы модуля. Из доков «Binding an instance is equivalent to passing an instance to a module constructor and providing that instance, but is often more efficient. When possible, binding object instances should be preferred to using module instances.»
0
Спасибо за отзыв, согласен с вашими комментариями и спасибо за дополнительные варианты)
0
«Если заглянуть в код DispatchingAndroidInjector#maybeInject, то видно что там создается инстанс билдера». Создается инстанс сабкомпонента, а не билдера — напутал.
0
«Но если у нас в активити инджектится DispatchingAndroidInjector (для внедрения фрагментов), то ссылка на сабкомпонент активити замкнется через билдер сабкомпонента фрагмента (так как он является inner классом).»
Замкнется через провайдер билдера сабкомпонента фрагмента — напутал.
Замкнется через провайдер билдера сабкомпонента фрагмента — напутал.
0
Мы можем добавить BindsInstance методы в билдер, отнаследованный от AndroidInjector.Factory. Далее переопределяем метод seedInstance у билдера, и вызываем все методы BindsInstance, при этом достаем параметры из активити/фрагмента переданного аргументом в seedInstance.
А можно пример кода? пока что тяжело понять… Спасибо!
0
Пример
@Subcomponent
public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {
@Override
public void seedInstance(MainActivity instance) {
someInteger(instance.getInt());
someString(instance.getString());
}
@BindsInstance
public abstract Builder someInteger(Integer integer);
@BindsInstance
public abstract Builder someString(String string);
}
}
Таким образом в граф добавятся Integer и String из активити и их можно будет инджектить.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Dagger 2.11 & Android. Часть 2