Кинжал @Развернутый масштаб vs @Singleton

Из Руководство пользователя:

Иногда вы хотите ограничить количество раз, когда @Inject-built класс создается или вызывается метод @Provides, но вы не необходимо гарантировать, что тот же самый экземпляр используется во время время жизни любого конкретного компонента или подкомпонента.

Почему я должен использовать это вместо @Singleton?

Ответ 1

Используйте @Singleton, если вы полагаетесь на поведение и гарантии синглтона. Используйте @Reusable, если объект будет только @Singleton по соображениям производительности.


Привязки @Rusable имеют гораздо больше общего с привязками с незаданной областью, чем привязки @Singleton: вы говорите Dagger, что вы можете создать совершенно новый объект, но если там уже создан удобный объект, то Dagger может использовать его. Напротив, объекты @Singleton гарантируют, что вы всегда будете получать один и тот же экземпляр, который может быть намного дороже в реализации.

В общем, Dagger и DI предпочитают объекты с незаданной областью: создание нового объекта - это отличный способ сохранить состояние в жестком состоянии и позволяет собирать мусор как можно скорее, как зависимый объект. Кинжал показывает некоторые из этих встроенных предпочтений: В Кинжале объекты с незаданной областью могут быть смешаны с любым компонентом или модулем, независимо от того, аннотирован ли компонент компонентом. Этот тип привязки с незаданной областью также полезен для объектов без состояния, таких как внедряемые (mockable) служебные классы и реализации стратегии, команд и других шаблонов полиморфного поведения: объекты должны быть связаны глобально и внедрены для тестирования/переопределений, но экземпляры этого не делают. сохранить любое состояние и недолгим или одноразовым.

Однако в Android и других средах performance- и с ограниченным объемом памяти создание большого количества временных объектов идет вразрез с рекомендациями по производительности, поскольку создание экземпляров и сборка мусора являются более дорогостоящими процессами, чем на настольных виртуальных машинах. Это приводит к прагматическому решению пометить объект @Singleton не потому, что важно всегда получать один и тот же экземпляр, а просто для сохранения экземпляров. Это работает, но семантически слабо, а также имеет последствия для памяти и скорости: ваш недолговечный объект утилит или шаблон стратегии теперь должен существовать до тех пор, пока существует ваше приложение, и доступ к нему должен осуществляться через двойную проверку блокировки, иначе вы рискуете нарушить гарантию @Singleton "только один экземпляр" (в этом нет необходимости). Это может быть источником повышенного использования памяти и накладных расходов на синхронизацию.

Компромисс заключается в связываниях @Reusable, которые имеют свойства сохранения экземпляра, такие как @Singleton, но исключаются из правила @Component сопоставления контекста, как и привязки с незаданной областью, что дает вам больше гибкости в отношении того, где вы их устанавливаете. (См. Тесты.) Они имеют срок службы только до тех пор, пока внешний компонент, который использует их напрямую, будет случайным образом использовать экземпляр от предка для сохранения в дальнейшем, но без двойной проверки блокировки, чтобы сэкономить на затратах на создание. Наконец, и самое главное, они дают вам и будущим разработчикам сигнал о том, как этот класс предназначен для использования.

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


Следующий вопрос от saiedmomen : "Чтобы быть на 100% понятными, такие как okhttpclient, retrofit и gson, должны быть объявлены @Reusable. Правильно??"

Да, в общем, я думаю, что было бы хорошо объявить утилиты и библиотеки без сохранения состояния как @Reusable. Однако, если они тайно сохраняют какое-то состояние - например, обрабатывают лимиты соединений или пакетную обработку для всех потребителей - вы можете захотеть сделать их @Singleton, и если они используются очень редко из долгоживущего компонента, все равно может иметь смысл сделать их бесполезными так что они могут быть собраны мусором. Здесь действительно сложно сделать общее утверждение, которое работает для всех случаев и библиотек: вам придется выбирать, основываясь на функциональности библиотеки, весе памяти, стоимости создания экземпляра и ожидаемой продолжительности жизни задействованных объектов.