Ответ
Lazy<T> и Provider<T> в Dagger используются для отложенного получения зависимостей, но с разной семантикой:
- Provider
- Каждый вызов
get()создаёт новый инстанс (если зависимость не@Singleton) - Подходит для случаев, когда нужны множественные экземпляры
- Каждый вызов
@Inject lateinit var provider: Provider<HeavyService>
// Каждый вызов создаёт новый объект:
val service1 = provider.get()
val service2 = provider.get() // service1 != service2
- Lazy
- Ленивая инициализация: объект создаётся только при первом вызове
get() - Последующие вызовы возвращают тот же инстанс (даже для non-Singleton)
- Потокобезопасен
- Ленивая инициализация: объект создаётся только при первом вызове
@Inject lateinit var lazyService: Lazy<HeavyService>
// Объект создаётся только здесь:
val service = lazyService.get()
// Возвращает тот же инстанс:
val sameService = lazyService.get()
Ключевое отличие: Provider всегда создаёт новый объект, Lazy кэширует результат после первого вызова.
Ответ 18+ 🔞
А, ну это классика, ебать мои старые костыли! Сидишь такой, ковыряешься в Dagger, и тут бац — два варианта, которые вроде бы одно и то же делают, но нихуя. Lazy<T> и Provider<T>. Чувак, тут разница тоньше, чем между «пойду поем» и «пойду пожру».
Смотри, вот Provider<T> — это как джинн из бутылки, только ебаный. Каждый раз, когда ты его вызываешь через provider.get(), он выдает тебе новый объект. Представь, что у тебя есть фабрика по производству табуреток. Ты кричишь: «Эй, Provider, дай табуретку!» — и он тебе одну выкатывает. Крикнул ещё раз — он, не моргнув глазом, выкатывает вторую, абсолютно новую. Это овердохуища удобно, когда тебе нужно несколько независимых экземпляров одной и той же хрени. Например, ты создаёшь кучу одноразовых уведомлений или временных сервисов. Каждый вызов get() — это новый чел, новая жизнь.
@Inject lateinit var stoolProvider: Provider<Stool>
// Заказываем две табуретки
val stoolForMe = stoolProvider.get() // Собрали первую
val stoolForYou = stoolProvider.get() // Собрали вторую, другую!
// stoolForMe != stoolForYou — это факт, ёпта.
А теперь Lazy<T> — это уже хитрая жопа. Это не фабрика, а скорее такой ленивый кот, который спит до последнего. Ты объявляешь: «Вот тут у меня будет тяжёлый сервис, Lazy<HeavyService>». И всё. Он нихуя не создаётся. Сидит, бздит, места в памяти почти не занимает. А в тот самый момент, когда ты впервые говоришь lazyService.get(), он просыпается, охуевает от того, что его потревожили, один раз создаёт объект и навсегда его запоминает. Все последующие вызовы get() будут возвращать тебе один и тот же, уже готовый инстанс. Даже если твой сервис не помечен как @Singleton! Потокобезопасно, удобно, волнение ебать — ноль.
@Inject lateinit var lazyHeavyService: Lazy<DatabaseConnection>
// Тишина, спокойствие. Объекта ещё нет.
// ...
// Пользователь тыкнул кнопку, пора работать:
val connection = lazyHeavyService.get() // Вжух! Создалось соединение (в первый и последний раз)
// ...
// Где-то в другом месте:
val sameConnection = lazyHeavyService.get() // А вот тут уже просто вернули то, что создали ранее. Никакой магии.
Итог, чтобы впендюрить в башку:
Provider— «дай мне ещё одну новенькую». Каждыйget()= новый объект.Lazy— «создай один раз, когда попросят в первый раз, и потом давай его же». Первыйget()= создание, остальные = возврат кэша.
Выбирай, исходя из того, что тебе надо: плодить сущности или один раз проинициализировать и забыть. Всё просто, как ёперный театр.