Области действия Dagger2 и жизненный цикл активности

У меня есть активность Android, в которую я использую Dagger2 для внедрения Presenter. Я бы хотел, чтобы мой Presenter мог сохранять состояние, даже если происходит изменение конфигурации.

Например, я собираюсь использовать Presenter для запуска сетевого вызова, и если пользователь поворачивает устройство во время выполнения сетевого вызова, я хотел бы иметь возможность получать ответ после того, как устройство завершит свое вращение и не нужно перезапускать вызов.

Я сбиваюсь с толку, потому что, если я охватываю экземпляр Presenter жизнью Activity, то нет ли шанса, что Presenter будет собирать мусор, когда Activity проходит через onDestroy() во время изменения конфигурации? Другая моя мысль заключалась в том, чтобы использовать область действия, которая действительна в течение всего срока службы приложения. Однако, если я это сделаю, как я могу гарантировать, что мой Presenter может быть собран мусором после того, как действие было уничтожено навсегда (не из-за изменения конфигурации, а из-за нажатия кнопки «Назад»)?

Есть ли способ гарантировать, что мой Presenter выживет после изменения конфигурации Activity, а также не будет утечек в течение жизни приложения?


person neonDion    schedule 25.01.2017    source источник


Ответы (2)


Я бы настоятельно рекомендовал не пытаться реализовать этот подход.

Вы эффективно пытаетесь использовать DI-инфраструктуру для поддержки Activity определенного потока жизненного цикла, хотя DI-инфраструктуры не предназначены для такого использования.

Недавно я ответил на другой аналогичный вопрос, в котором OP пытался разделить состояние в View-Model между разными Activities. Хотя варианты использования не идентичны, общая схема одна и та же — попытка делегировать обязанности по управлению потоком на платформу DI, что не является хорошей идеей.

Лучшим подходом в вашем случае (IMHO) было бы сохранение текущего состояния перед вращением, повторное создание экземпляра ведущего при вращении, а затем восстановление его состояния.

То, как вы сохраняете состояние во время вращения, зависит от того, что именно вы пытаетесь сохранить:

  • Если вам нужно сохранить состояние, связанное с пользовательским интерфейсом (выборки, тексты, положение элементов и т. д.), вы можете использовать обычные обратные вызовы onSaveInstanceState() и onRestoreInstanceState().
  • Если вам нужно сохранить некоторое состояние, связанное с бизнесом (текущие сетевые запросы, данные, модификации данных и т. д.), инкапсулируйте эту логику в бизнес-класс (например, SomeBusinessUseCaseManager) и внедрите этот класс из компонента Application с областью действия.

Вы можете найти подробный обзор прицелов Dagger здесь.

Дополнительную информацию о внедрении зависимостей в Android можно найти здесь.

person Vasiliy    schedule 26.01.2017
comment
Ваша вторая рекомендация аналогична тому, что я делаю со своим Presenter. В Presenter есть несколько внедренных UseCase (я создаю экземпляры UseCase в Activity и внедряю в Presenter с помощью конструктора). Если я перенесу экземпляр UseCase в компонент, который живет на протяжении всего срока службы приложения, тогда UseCase может продолжать работать во время конфигурации. измениться, и когда после config. измените его, чтобы ввести уже запущенные варианты использования. Это решает проблему необходимости переделывать то, что уже было начато. - person neonDion; 26.01.2017
comment
@neonDion, звучит как хороший план. Обратите внимание, что если вы сделаете это, вы получите дополнительную выгоду от выхода из презентаторов и абстрагирования вещей, связанных с сетью. Это большой шаг к раздельному дизайну. - person Vasiliy; 26.01.2017

Согласно этой статье о пользовательских областях:

http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/

Короче говоря, области действия дают нам «локальные синглетоны», которые живут столько же, сколько и область действия.

Просто для ясности: по умолчанию в Dagger 2 нет аннотаций @ActivityScope или @ApplicationScope. Это просто наиболее распространенное использование пользовательских областей. По умолчанию доступна только область @Singleton (предоставляется самой Java), и дело в том, что использования области недостаточно (!) и вы должны позаботиться о компоненте, который содержит эту область. Это означает сохранение ссылки на него внутри класса Application и его повторное использование при изменении Activity.

public class GithubClientApplication extends Application {

    private AppComponent appComponent;
    private UserComponent userComponent;

    //...

    public UserComponent createUserComponent(User user) {
        userComponent = appComponent.plus(new UserModule(user));
        return userComponent;
    }

    public void releaseUserComponent() {
        userComponent = null;
    }

    //...
}

Вы можете взглянуть на этот пример проекта:

http://github.com/mmirhoseini/marvel

и эта статья:

https://hackernoon.com/yet-another-mvp-article-part-1-lets-get-to-know-the-project-d3fd553b3e21

чтобы лучше познакомиться с MVP и узнать, как работает прицел кинжала.

person Mohsen Mirhoseini    schedule 25.01.2017
comment
В ваших ссылках много информации. Можете ли вы добавить в свой ответ краткий обзор, который отвечает на вопрос: есть ли способ гарантировать, что мой Presenter выдержит изменение конфигурации Activity, а также не будет просочиться в течение жизни приложения? - person neonDion; 26.01.2017
comment
Хорошо, тогда я отредактирую ответ, но хотя бы взгляните на это, потому что необходимо знать, что области действия — это просто тег, и, к сожалению, они ничего не делают, и вы должны со всем справиться: frogermcs.github.io/ - person Mohsen Mirhoseini; 26.01.2017