Pull to refresh

Comments 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.»
Спасибо за отзыв, согласен с вашими комментариями и спасибо за дополнительные варианты)
«Если заглянуть в код DispatchingAndroidInjector#maybeInject, то видно что там создается инстанс билдера». Создается инстанс сабкомпонента, а не билдера — напутал.
«Но если у нас в активити инджектится DispatchingAndroidInjector (для внедрения фрагментов), то ссылка на сабкомпонент активити замкнется через билдер сабкомпонента фрагмента (так как он является inner классом).»
Замкнется через провайдер билдера сабкомпонента фрагмента — напутал.
Мы можем добавить BindsInstance методы в билдер, отнаследованный от AndroidInjector.Factory. Далее переопределяем метод seedInstance у билдера, и вызываем все методы BindsInstance, при этом достаем параметры из активити/фрагмента переданного аргументом в seedInstance.

А можно пример кода? пока что тяжело понять… Спасибо!

Пример
@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 из активити и их можно будет инджектить.
Sign up to leave a comment.

Articles