Когда стоит использовать Provides в Dagger

Ответ

@Provides используется в Dagger для указания способа создания объекта, когда:

  1. Объект нельзя создать через @Inject (например, интерфейсы или сторонние библиотеки).
  2. Требуется кастомизация создания (например, конфигурация Retrofit или OkHttpClient).
  3. Зависимость требует runtime-аргументов (через @BindsInstance или параметры в модуле).

Пример:

@Module
class NetworkModule {
    @Provides
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .build()
    }
}

⚠️ Если можно использовать @Inject или @Binds (для интерфейсов), лучше выбрать их — код будет чище.

Ответ 18+ 🔞

А, ну это же классика, ёпта! Смотри, сейчас разжуём, что за зверь такой — @Provides.

Представь, что Dagger — это такой дотошный прораб на стройке твоего приложения. Он готов сам замешивать бетон и класть кирпичи, но только если ты дашь ему чёткую схему, как это делать. @Inject на конструкторе — это как сказать: «Вот, прораб, беги на склад, там все детали для «Мустанга» лежат, собери мне его». А @Provides — это когда деталь настолько хитрая или нестандартная, что тебе приходится самому лезть в ящик с инструментами и буквально руками показывать, как её скрутить.

Когда этот твой @Provides реально нужен?

  1. Когда объект — это интерфейс или абстрактный класс. Ну ясно же, ёбать копать, его нельзя просто «newнуть»! Dagger смотрит на SomeInterface и такой: «Чувак, а какую конкретную реализацию тебе запихнуть? Я не телепат, блядь». Вот тут ты и пишешь метод, который говорит: «На SomeInterface — вот этот вот SomeImplementation и возвращай».

  2. Когда объект из чужой библиотеки. Retrofit, OkHttpClient, Gson — ты же не можешь в их исходники залезть и @Inject в конструктор впендюрить? Придётся самому, вручную, в модуле объяснять Dagger'у, как эту штуку собрать. Это прям его родная стихия.

  3. Когда создание — это целый ритуал. Допустим, тебе нужен не просто OkHttpClient, а такой, который с таймаутами, логгером и интерцепторами. Вот тут ты разворачиваешься и в методе с @Provides пишешь целую поэму из Builder().

Смотри, как это выглядит на практике, чтобы совсем ни хуя себе не осталось:

@Module
class NetworkModule {

    @Provides
    fun provideOkHttpClient(): OkHttpClient {
        // Вот тут ты — бог и царь. Настраивай как хочешь.
        return OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS) // Чтоб не тупил
            .addInterceptor(LoggingInterceptor()) // Чтоб всё логировал
            .build()
    }

    @Provides
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        // А сюда Dagger сам подсунет тот OkHttpClient, что мы создали выше. Красота!
        return Retrofit.Builder()
            .baseUrl("https://api.mojservis.ru/")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}

НО! Важное предупреждение, чтоб потом не было волнения ебать.
Если можно обойтись без этого — обходись. Если класс твой, и в его конструктор можно воткнуть @Inject — делай так. Если привязываешь интерфейс к реализации — сначала посмотри на @Binds, он часто лаконичнее. @Provides — это как мощная дрель: для гипсокартона она овердохуища, но чтобы повесить картину, хватит и молотка с гвоздём. Не усложняй без нужды, а то получится пиздопроебибна с модулями на ровном месте.