Hitech logo

Кейсы

Объяснение Dagger Custom Scope на примере

TODO:
Роман Савицкий14 апреля 2022 г., 08:37

Как многие знают, по-умолчанию Dagger создает для нас новые объекты каждый раз, когда мы запрашиваем внедрение зависимостей. Но иногда мы хотим переиспользовать ранее созданные объекты, и в этом случае нам поможет Scope. Как именно это можно сделать, рассказал Android-разработчик Магомед-Хусейн Закриев.

Самые интересные технологические и научные новости выходят в нашем телеграм-канале Хайтек+. Подпишитесь, чтобы быть в курсе.

В качестве примера возьмем простое Android-приложение, состоящее только из одного Activity. В нем создадим 2 компонента Dagger: ApplicationComponent, жизненный цикл которого совпадает с жизненным циклом приложения, и ActivityComponent, жизненный цикл которого совпадает с жизненным циклом Activity. Как известно, при смене конфигурации, Activity пересоздается, поэтому ActivityComponent также будет пересоздаваться. Также, нам в ActivityComponent, возможно, понадобятся зависимости из ApplicationComponent, поэтому сделаем ActivityComponent субкомпонентом ApplicationComponent.

Для начала объявим ApplicationScope и ActivityScope:

Теперь объявим ApplicationComponent и ActivityComponent

Далее объявим наследника от класса Application, создадим ApplicationComponent в его методе onCreate и сохраним созданный объект в поле наследника класса Application.

Теперь перейдем в MainActivity, создадим в методе onCreate ActivityComponent и запросим зависимости с помощью метода inject:

Но пока нам нечего инджектить, поэтому создадим демонстрационный класс Example:

При каждом создании объекта класса Example, ему будет присвоен уникальный идентификатор, который поможет нам в последующем понять создал ли нам Dagger новый объект этого класса или переиспользовал старый.

Теперь вернемся в MainActivity, добавим поле example, которое мы будем запрашивать у Dagger через ActivityComponent, и напишем вывод в лог идентификатора объекта:

Запустим приложение и получим вывод в лог:

Теперь повернем экран, чтобы активити пересоздалось и снова запросило зависимости. Получаем:

Как и ожидалось, Dagger создал новый объект при повторном запросе зависимостей.

Теперь укажем ActivityScope для класса Example:

Но поведение не поменяется. При каждом повороте экрана, Dagger будет создавать новый объект. Потому что при пересоздании Activity, ActivityComponent также пересоздается. Но мы почуствуем разницу, если захотим переиспользовать объект класса Example в пределах жизненного цикла Activity, то есть до того, как оно будет пересоздано. Для этого объявим класс ExampleHolder, который запрашивает объект класса Example через конструктор:

Теперь добавим поле exampleHolder в MainActivity и выведем в лог идентификатор объекта example, который он содержит:

Посмотрим лог:

Перевернем экран:

Мы видим, что в пределах одного Activity используется один и тот же объект. Это потому что мы задали ему скоуп который совпадает со скоупом ActivityComponent. Если мы сотрем скоуп у класса Example, то получим:

А после пересоздания экрана:

То есть объект не переиспользуется, а создается каждый раз, когда запрашивается.

Вспомним, что ActivityComponent является субкомпонентом ApplicationComponent, который создается только один раз — при создании приложения. А значит его жизненный цикл совпадает с жизненным циклом всего приложения. Давайте попробуем указать для класса Example скоуп ApplicationScope и посмотрим, что у нас получится.

Вывод в лог будет следующий:

А после пересоздания экрана:

Как видим, Dagger не создает новый объект при пересоздании Activity, а переиспользует один и тот же объект в пределах жизненного цикла всего приложения.