Подтвердить что ты не робот

Область и подкомпоненты кинжала 2

Я пытаюсь улучшить свое приложение и код с большей поддержкой, используя Dagger2. Я понял общую идею, но до сих пор не могу понять, как управлять областями с помощью Dagger2 Я вложил кинжал в свой проект (звучит смешно). Я создал компонент ApplicationComonent, и он отлично работает в моем проекте. Вот мой код.

@Singleton
@Component(modules = {
        ApplicationModule.class,
        ThreadingModule.class,
        NetworkModule.class,
        DatabaseModule.class,
        ServiceModule.class,
        ParseModule.class,
        PreferencesSessionModule.class})

public interface ApplicationComponent {
    ActivityComponent activityComponent(ActivityModule activityModule);

    void inject(BaseActivity baseActivity);

    void inject(MainAppActivity mainAppActivity);

    void inject(MyApplication application);

    void inject(BaseFragment baseFragment);

    void inject(MyService service);

    void inject(RegistrationIntentService service);
}

Я создаю экземпляр компонента в классе MyApplication, как этот

private void initializeAndInjectComponent() {
        mApplicationComponent =
                DaggerApplicationComponent
                        .builder()
                        .threadingModule(new ThreadingModule(1))
                        .applicationModule(new ApplicationModule(this))
                        .networkModule(new NetworkModule(
                                MyService.API_SERVER_BASE_URL,
                                MyService.TIMEOUT))
                        .build();
        mApplicationComponent.inject(this);
    }

И я могу получить компонент для ввода в моем Activities

    MyApplication application = MyApplication.get(this);
    application.getApplicationComponent().inject(this);

Все работает отлично.

Чтобы добавить каждый метод, а также класс модуля, аннотируется с областью @Singleton, все модули, относящиеся к ApplicationComponent

Теперь я хочу улучшить зависимости, и я видел множество примеров с пользовательскими областями, например @PerActivity, @PerFragment. У меня много вопросов, но об этом позже.

Итак, я создал ActivityComponent

@PerActivity
@Subcomponent(
        modules = {
                NetworkServiceModule.class,
                ActivityModule.class,
                PermissionModule.class
        })
public interface ActivityComponent {
    Activity activity();

    void inject(BaseActivity baseActivity);
}

Все модули выглядят как

@PerActivity
@Module
public class ActivityModule {
    private Activity mActivity;

    public ActivityModule(Activity activity) {
        this.mActivity = activity;
    }

    @Provides
    @PerActivity
    Activity provideActivity() {
        return this.mActivity;
    }
}

У меня есть следующие зависимости в моем BaseActivity

// Dependencies from ApplicationComponent
    @Inject
    protected ApplicationSettingsManager mApplicationSettingsManager;
    @Inject
    protected ScheduledThreadPoolExecutor mPoolExecutor;
// Dependencies from ActivityComponent
    @Inject
    protected SpiceManager mSpiceManager;
    @Inject
    protected PermissionController mPermissionController;

И в моем методе onCreate() я впрыскиваю следующее

    MyApplication application = MyApplication.get(this);
    application.getApplicationComponent().activityComponent(new ActivityModule(this)).inject(this);

До создания подкомпонента ActivityComponent это было

   MyApplication application = MyApplication.get(this);
        application.getApplicationComponent().inject(this);

Теперь я получил сообщение об ошибке

Error:(34, 10) error: com.octo.android.robospice.SpiceManager cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
BaseActivity.mSpiceManager
[injected field of type: com.octo.android.robospice.SpiceManager mSpiceManager]

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

Все, кроме @Singleton, игнорируется Кинжалом 2, верно? Я не понимаю, как управляется жизнь компонента? У меня есть только одна идея.

  • Когда вы используете @Singleton, кинжал-аннотация создает объект в каком-то статическом пуле, который будет существовать в течение всего жизненного цикла приложения, и будет уничтожен, когда экземпляр JVM-процесса (dalvik VM, ART) будет уничтожен.

  • Когда вы используете какую-либо другую аннотацию, для вас, как разработчика, лучше поддерживать код, @PerActivity, @PerFragment - это просто нестандартная аннотация. И если вы разместите компонент @PerFragment в классе Application, он будет жить до тех пор, пока приложение будет работать. Я прав?

  • Итак, я понимаю это так: если кинжал найдет аннотацию @Singleton, она добавит статическую ссылку на компонент, когда она будет создана впервые, а в случае любой другой аннотации она не будет ссылаться на компонент.

Я был бы очень благодарен за любую помощь в описанных выше проблемах.

UPDATE

Спасибо David Medenjak за отличный ответ, я получил гораздо лучшее понимание Dagger2.

Я также нашел проблему, поскольку теперь я использую отдельный компонент Activity, я забыл о двух строках в ApplicationComponent и изменил inejction в моих MainActivity на ActivityComponent вместо ApplicationComponent, поэтому наверняка не удалось разрешить зависимости от подкомпонента.

 void inject(BaseActivity baseActivity);

 void inject(MainAppActivity mainAppActivity);

Теперь все работает отлично, мне нравится Dagger2 и разделенная архитектура.

4b9b3361

Ответ 1

Немного радикально, но для упрощения вещей: Все аннотации Scope - не что иное, как синтаксический сахар, включая @Singleton.

Области в основном просто обеспечивают проверку времени компиляции. Циклические зависимости, или ошибки о вещах, которые вы, возможно, пропустили. @Singleton точно так же, как и любая другая область, единственное отличие состоит в том, что это уже существующая аннотация, и вам не нужно ее создавать самостоятельно. Вместо этого вы можете использовать @MySingleton.

[...] кинжал создает объект в некотором статическом пуле, который будет существовать в течение всего жизненного цикла приложения

Нет. Кинжал ничего не статично. У вас есть компоненты. Эти компоненты содержат ваши объекты, созданные модулями. Если объект в компоненте имеет область действия компонента, он будет создан только один раз в этом точном компоненте. Если вы решили создать 2 AppComponent объекта, у вас будет 2 объекта каждого аннотированного объекта @Singleton, каждый из которых будет находиться внутри его компонента. Вот почему вы должны сохранить ссылку на компонент. Большинство реализаций, которые я видел или использовал, сохраняют их AppComponent в пределах Application. Если вы сделаете это, вы можете использовать его как singleton &mdash, это все еще просто POJO.

[...] вы размещаете компонент @PerFragment в классе Application, он будет работать до тех пор, пока Application будет работать.

Да. Как уже описано выше, это просто объект. Сохраните ссылку, вы держите объекты. Выбросьте его или создайте новый, и у вас есть новые объекты (определенные внутри этого компонента/области). Вы должны, хотя и не сохранять компоненты, зависящие от активности или фрагмента, в каком-либо месте, кроме как в действиях или фрагментах, соответственно, так как их хранение, например. в вашем компоненте приложения, скорее всего, приведет к утечке памяти. (Если это не так, вам, вероятно, не понадобится область действия или фрагмента.)

Если кинжал найдет аннотацию @Singleton, она добавит статическую ссылку на компонент, когда она будет создана впервые, а в случае любой другой аннотации она не будет ссылаться на компонент.

Опять же, нет. Ничего статичного. Обычные старые объекты java. У вас может быть несколько компонентов @Singleton со своими собственными объектами, но вы, вероятно, не должны (хотя это то, что делает возможным тестирование инструментария /easy &mdash, просто заменяйте компоненты.)


Указанная ошибка

SpiceManager не может быть предоставлен без конструктора @Inject или из метода @Provides- или @Produces-annotated.

Это означает, что компонент, который вы пытаетесь ввести ваш объект, не может найти способ создать или предоставить SpiceManager. Убедитесь, что вы предоставили его из своего AppComponent или в каком-либо другом месте, не пропустите никаких комментариев и т.д.