๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Android

[Android] Dagger2 - @Provides

interfacer_han 2024. 6. 24. 08:48

#1 ์ด์ „ ๊ธ€

[Android] Dagger2 - ๊ธฐ์ดˆ

#1 ์ด์ „ ๊ธ€ ์˜์กด์„ฑ ์ฃผ์ž… (Dependency Injection)#1 ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection)์ด๋ž€?#1-1 Dependent์™€ Dependencyfun main() { val car = Car() car.startCar() } class Car { private val engine = Engine() private val airbag = Airbag() private

kenel.tistory.com

์œ„ ๊ฒŒ์‹œ๊ธ€์˜ ์™„์„ฑ๋œ ์•ฑ์„ ์ผ๋ถ€ ์ˆ˜์ •ํ•ด์„œ, @Inject๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์˜ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•ด๊ฒฐํ•ด๋ณธ๋‹ค.
 

#2 @Provides

์ด์ „ ๊ธ€์—์„  ์ƒ์„ฑ์ž์— @Inject๋ฅผ ๋ถ™์˜€๊ณ , ๊ทธ๊ฒƒ์€ dagger๊ฐ€ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•˜๋Š” ๋ช…์‹œ์ ์ธ ํ‘œ์‹œ๋กœ์„œ ์ž‘๋™ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ, ์ƒ์„ฑ์ž์— @Inject๋ฅผ ๋ถ™์ธ๋‹ค๋Š” ๊ฒƒ์€ ๊ทธ ํ–‰๋™์˜ ๋ฒ”์œ„๊ฐ€ ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋กœ ์ œํ•œ๋œ๋‹ค๋Š” ๋ง์ด๊ธฐ๋„ ํ•˜๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ๊ฒƒ์€ ๋ฌด์—‡์ผ๊นŒ? String, Int ๋“ฑ๊ณผ ๊ฐ™์€ ๊ธฐ๋ณธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ถ€ํ„ฐ Retrofit, Room ๋“ฑ ์ œ 3์ž ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค. ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ํ•ด๋‹น ํด๋ž˜์Šค๋“ค์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์„ค๋ น ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ•ด๋„ ๊ทธ ๋ฐฉ๋Œ€ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฑด๋“ค์ด๋Š” ๊ฒƒ์€ ๊ถŒ์žฅ๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.
 
์ด๋Ÿด ๋•Œ @Inject ๋Œ€์‹  ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด @Provides๋‹ค. ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋‚ด๊ฒŒ ์ œ๊ณต(Provides)๋œ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ๋ชฉ์ ์ด๋‹ค.
 
์ถ”๊ฐ€๋กœ, @Inject๋กœ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•˜๋Š” ๊ฒƒ์ด ์ด๋ก ์ƒ ๊ฐ€๋Šฅํ•จ์—๋„ @Provides๋ฅผ ์„ ํƒํ•ด ์“ฐ๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค. ๋ฐ”๋กœ, ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ์— ๋ณต์žกํ•œ ๋กœ์ง์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ๊ทธ๋ ‡๋‹ค.
 

#3 ์ฝ”๋“œ ์ˆ˜์ • - @Provides ์‚ฌ์šฉ

#3-1 Dependency ์ถ”๊ฐ€

์œ„์™€ ๊ฐ™์ด ๊ธฐ์กด ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„์—์„œ Airbag์ด Stringํ˜•์ธ Dependency๋ฅผ ์š”๊ตฌํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. String์€ ์ฝ๊ธฐ ์ „์šฉ ํด๋ž˜์Šค๋‹ค. ์ฆ‰, @Provides๋กœ ์ œ๊ณต๋˜์–ด์•ผ ํ•œ๋‹ค.
 

// package com.example.provides

import android.util.Log
import javax.inject.Inject

class Airbag @Inject constructor(private val manufacturer: String) {
    fun startAirbag() {
        Log.i("interfacer_han", "${this::class.simpleName} is ready")
        Log.i("interfacer_han", "${this::class.simpleName} made by ${manufacturer}")
    }
}

Airbag ํด๋ž˜์Šค์˜ ์ฝ”๋“œ๋Š” ์ด ์ •๋„๋กœ ์ˆ˜์ •ํ•œ๋‹ค.
 

#3-2 @Module

// package com.example.provides

import dagger.Module

@Module
class MyModule {

    // TODO: @Provides ๋ฉ”์†Œ๋“œ ๋งŒ๋“ค๊ธฐ
}

์ด์ „ ๊ธ€์— ์˜ํ•˜๋ฉด, @Component ํด๋ž˜์Šค๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ์Šค์บ”ํ•˜๋ฉฐ @Inject๊ฐ€ ๋ถ™์€ ์ƒ์„ฑ์ž๋‚˜ @Provides๊ฐ€ ๋ถ™์€ ๋ฉ”์†Œ๋“œ๋ฅผ ์ฐพ๋Š”๋‹ค. ์•”์‹œ์  ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•˜๋Š” ์ฃผ์ฒด๊ฐ€ @Component ํด๋ž˜์Šค์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. @Provides ๋ฉ”์†Œ๋“œ๋Š” ๋ฐ˜๋“œ์‹œ๋Š” ์•„๋‹ˆ์ง€๋งŒ ๊ฑฐ์˜ ๋Œ€๋ถ€๋ถ„ @Module ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์ •์˜๋œ๋‹ค. @Module ์—ญํ• ์„ ํ•  ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋‹ค.
 

#3-3 @Component

// package com.example.provides

import dagger.Component

@Component(modules = [MyModule::class])
interface CarComponent {
    fun getCar(): Car
}

Component ์ธํ„ฐํŽ˜์ด์Šค์— @Module ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ์ด ์‹œ์ ๋ถ€ํ„ฐ, Component ํด๋ž˜์Šค๋Š” ์˜์กด์„ฑ ์ฃผ์ž…์„ ์œ„ํ•œ @Inject ๋ฐ @Provides์˜ ์Šค์บ” ๋ฒ”์œ„์— MyModule ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
 

#3-4 @Provides

// package com.example.provides

import dagger.Module
import dagger.Provides

@Module
class MyModule {

    @Provides
    fun providesAirbagManufacturer(): String {
        return "KENEL"
    }
}

MyModule ํด๋ž˜์Šค์— String์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
 

#3-5 ์ž‘๋™ ํ™•์ธ (๋กœ๊ทธ ๋ฉ”์‹œ์ง€)

Crankshaft is ready
Cylinder is ready
Piston is ready
Engine is ready
Airbag is ready
Airbag made by KENEL
Battery is ready
Car is ready

 

#4 ์ฝ”๋“œ ์ˆ˜์ • - @Named ์‚ฌ์šฉ

#4-1 @Provides์˜ ๋ฐ˜ํ™˜ํ˜•์ด ์ค‘๋ณต๋œ๋‹ค๋ฉด?

๋งŒ์•ฝ, Battery๋„ Airbag๊ณผ ๊ฐ™์€ ๋ฐ์ดํ„ฐํ˜•์ธ Dependency๋ฅผ ์š”๊ตฌํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?
 

// package com.example.provides

import android.util.Log
import javax.inject.Inject

class Battery @Inject constructor(private val manufacturer: String) {
    fun startBattery() {
        Log.i("interfacer_han", "${this::class.simpleName} is ready")
        Log.i("interfacer_han", "${this::class.simpleName} made by ${manufacturer}")
    }
}

์ผ๋‹จ Battery ํด๋ž˜์Šค๋ฅผ ์œ„์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.
 

// package com.example.provides

import dagger.Module
import dagger.Provides

@Module
class MyModule {

    @Provides
    fun providesAirbagManufacturer(): String {
        return "KENEL"
    }

    @Provides
    fun providesBatteryManufacturer(): String {
        return "TISTORY"
    }
}

๊ทธ๋ฆฌ๊ณ  @Module ํด๋ž˜์Šค๋Š” ์ด๋ ‡๊ฒŒ ์ˆ˜์ •ํ•ด๋ณธ๋‹ค.
 

#4-2 ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ ์‹œ ๋œจ๋Š” ์—๋Ÿฌ ๋ฉ”์‹œ์ง€

error: [Dagger/DuplicateBindings] java.lang.String is bound multiple times

dagger ์ž…์žฅ์—์„œ, ์–ด๋–ค @Provides ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š” ์ง€ ๊ฒฐ์ •ํ•  ์ˆ˜ ์—†๊ธฐ์— ๋œจ๋Š” ์—๋Ÿฌ๋‹ค. dagger๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ํ˜•์„ ๊ธฐ์ค€์‚ผ์•„ ์•”์‹œ์  ์˜์กด์„ฑ ์ฃผ์ž…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ๋ฐ˜ํ™˜ํ˜•์ด ์ค‘๋ณต๋˜๋Š” ํ˜„ ์‹œ์ ์—์„ , dagger๊ฐ€ ์˜์กด์„ฑ ์ฃผ์ž…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์žˆ์–ด ๋˜ ๋‹ค๋ฅธ ๊ธฐ์ค€ ์š”์†Œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
 
์—ฌ๋‹ด์œผ๋กœ, ํ•จ์ˆ˜ ์ด๋ฆ„(์—ฌ๊ธฐ์„œ๋Š” providesAirbagManufacturer() ๋ฐ providesBatteryManufacturer())์€ dagger ์ž…์žฅ๊ณผ ๋‹น์—ฐํžˆ ๊ด€๋ จ์ด ์—†๋‹ค. ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์€ ํ”„๋ž˜๊ทธ๋ž˜๋จธ ์ž…์žฅ์—์„œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ๊ด€๋ จ๋œ ์š”์†Œ์ผ ๋ฟ์ด๋‹ค.
 

#4-3 @Named ์‚ฌ์šฉ - @Module์—์„œ

...
import javax.inject.Named

@Module
class MyModule {

    @Provides
    @Named("Airbag")
    fun providesAirbagManufacturer(): String {
        return "KENEL"
    }

    @Provides
    @Named("Battery")
    fun providesBatteryManufacturer(): String {
        return "TISTORY"
    }
}

๊ทธ ๋˜ ๋‹ค๋ฅธ ์š”์†Œ๋Š” ๋ฐ”๋กœ @Named ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค. @Named๋Š” ๋™์ผํ•œ ๋ฐ์ดํ„ฐ ํƒ€์ž…์ธ Dependency๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ์žˆ์„ ๋•Œ ๊ฐ๊ฐ์˜ Dependency๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋œ๋‹ค.
 

#4-4 @Named ์‚ฌ์šฉ - @Inject์—์„œ

...
import javax.inject.Named

class Airbag @Inject constructor(@Named("Airbag") private val manufacturer: String) {
    fun startAirbag() {
        Log.i("interfacer_han", "${this::class.simpleName} is ready")
        Log.i("interfacer_han", "${this::class.simpleName} made by ${manufacturer}")
    }
}

@Inject๊ฐ€ ๋ถ™์€ ์ƒ์„ฑ์ž์˜ ์ธ์ˆ˜์—๋„ #4-3์™€ ๋งค์นญ๋˜๋Š” @Named ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ค€๋‹ค.
 

#4-5 ์ž‘๋™ ํ™•์ธ (๋กœ๊ทธ ๋ฉ”์‹œ์ง€)

Crankshaft is ready
Cylinder is ready
Piston is ready
Engine is ready
Airbag is ready
Airbag made by KENEL
Battery is ready
Battery made by TISTORY
Car is ready

 

#5 ์š”์•ฝ

@Inject๊ฐ€ ๋ถˆ๊ฐ€ํ•œ ํด๋ž˜์Šค๋Š” @Provides๋กœ ์ œ๊ณต(Provide)ํ•˜๊ณ , ์ œ๊ณต๋˜๋Š” ๊ฒƒ๋ผ๋ฆฌ์˜ ๊ตฌ๋ถ„์€ @Named๋กœ ํ•œ๋‹ค.
 

#6 ์™„์„ฑ๋œ ์•ฑ

android-practice/dagger2/Provides at master ยท Kanmanemone/android-practice

Contribute to Kanmanemone/android-practice development by creating an account on GitHub.

github.com

 

#7 ์ด์–ด์ง€๋Š” ๊ธ€

[Android] Dagger2 - ๋งค๊ฐœ๋ณ€์ˆ˜

#1 ์ด์ „ ๊ธ€ [Android] Dagger2 - @Provides#1 ์ด์ „ ๊ธ€ [Android] Dagger2 - ๊ธฐ์ดˆ#1 ์ด์ „ ๊ธ€ ์˜์กด์„ฑ ์ฃผ์ž… (Dependency Injection)#1 ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection)์ด๋ž€?#1-1 Dependent์™€ Dependencyfun main() { val car = Car() car.startCar

kenel.tistory.com

์ด์–ด์ง€๋Š” ๊ธ€์—์„œ @Provides ๋˜๋Š” @Module์ด ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋งŒ๋“ค์–ด๋ณธ๋‹ค.