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

[Android] Dagger2 - Hilt๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

interfacer_han 2024. 7. 12. 16:50

#1 Hilt ๊ฐœ์š”

 

Hilt๋ฅผ ์‚ฌ์šฉํ•œ ์ข…์† ํ•ญ๋ชฉ ์‚ฝ์ž…  |  Android Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Hilt๋ฅผ ์‚ฌ์šฉํ•œ ์ข…์† ํ•ญ๋ชฉ ์‚ฝ์ž… ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ์š”. Hilt๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ์ข…์†

developer.android.com

Hilt๋Š” Dagger2์˜ ๋ณต์žกํ•œ ๋ถ€๋ถ„์„ ๋” ์‰ฝ๊ณ  ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์ถ”์ƒํ™” ๊ณ„์ธต์ด๋‹ค. ๊ทธ๋Ÿฐ ๋ฉด์—์„œ Dagger2 - Hilt ๊ด€๊ณ„๋Š” SQLite - Room์˜ ๊ด€๊ณ„์™€๋„ ๊ฐ™๋‹ค. Hilt์„ ์‚ฌ์šฉํ•˜๋ฉด Dagger2๋ฅผ ์ƒ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์„ธ์„ธํ•œ ์„ค์ •์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ํ•˜์ง€๋งŒ, ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ์ค„์—ฌ์ค€๋‹ค. ๋ง ๊ทธ๋Œ€๋กœ ์ถ”์ƒํ™” ๊ณ„์ธต์ด๋‹ˆ ๋ง์ด๋‹ค.
 

#2 Hilt ์‚ฌ์šฉํ•˜๊ธฐ -  ๊ธฐ์ดˆ

#2-1 Hilt๋ฅผ ์ ์šฉํ•  ์ƒ˜ํ”Œ ์•ฑ

 

[Android] Dagger2 - Activity์— Dependency ์ฃผ์ž…

#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

kenel.tistory.com

Dagger2๋ฅผ ์ด์šฉํ•ด ํ•„๋“œ ์ฃผ์ž…์„ ๊ตฌํ˜„ํ•œ ์œ„ ๊ฒŒ์‹œ๊ธ€์˜ ์™„์„ฑ๋œ ์•ฑ์„ ์ผ๋ถ€ ์ˆ˜์ •ํ•ด์„œ, ํ•ด๋‹น ์•ฑ์ด Dagger2 ๋Œ€์‹  Hilt๋ฅผ ์ด์šฉํ•ด ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด๋ณธ๋‹ค.
 

์ˆ˜์ •์„ ๊ฐ€ํ•  ์ƒ˜ํ”Œ ์•ฑ์˜ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋‹ค.
 

#2-2 build.gradle (ํ”„๋กœ์ ํŠธ ์ˆ˜์ค€)

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    ...

    // Hilt
    id("com.google.dagger.hilt.android") version "2.46" apply false
}

 

#2-3 build.gradle (๋ชจ๋“ˆ ์ˆ˜์ค€)

plugins {
    ...

    // Hilt
    id("com.google.dagger.hilt.android")
}

android {
    ...
}

dependencies {

    ...
/*
    // Dagger2
    val daggerVersion = "2.51.1"
    implementation("com.google.dagger:dagger:$daggerVersion")
    kapt("com.google.dagger:dagger-compiler:$daggerVersion")
*/
    // Hilt
    val hiltVersion = "2.46"
    implementation("com.google.dagger:hilt-android:$hiltVersion")
    kapt("com.google.dagger:hilt-android-compiler:$hiltVersion")
}

๊ธฐ์กด Dagger2์— ๊ด€ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ฃผ์„ ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด ์‚ญ์ œํ•ด๋ฒ„๋ ธ๋‹ค. Hilt ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ด๋ฏธ ํฌํ•จ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
 

#2-4 ์‚ฌ์šฉ์ž ์ •์˜ @Component ํด๋ž˜์Šค (CarComponent.kt) ์‚ญ์ œ

/* ์‚ญ์ œ

import dagger.Component

@Component
interface CarComponent {
    fun inject(mainActivity: MainActivity)
}

*/

Hilt๊ฐ€ Dagger2์™€ ๊ตฌ๋ณ„๋˜๋Š” ๊ฐ€์žฅ ํฐ ๋ถ€๋ถ„์€ ๋ฐ”๋กœ @Component ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๋งŒ๋“ค๋„๋ก ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด๋‹ค. Hilt์—์„œ๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ Component ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‹จ์—์„œ ์ด๋ฏธ ์ƒ์„ฑ๋œ ์ฑ„๋กœ ํ”„๋กœ๊ทธ๋ž˜๋จธ์—๊ฒŒ ์ œ๊ณต๋œ๋‹ค. ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” ๊ทธ ์ค‘์—์„œ ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ณจ๋ผ์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ตฌ์กฐ๋‹ค (์ฐธ์กฐ: Hilt์— built-in๋œ ์ปดํฌ๋„ŒํŠธ์˜ ๋ชฉ๋ก). ๋”ฐ๋ผ์„œ CarComponent.kt ํŒŒ์ผ์„ ์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์ ํŠธ์—์„œ ์ œ๊ฑฐํ•œ๋‹ค.
 

#2-5 Application ํด๋ž˜์Šค์— @HiltAndroidApp ์–ด๋…ธํ…Œ์ด์…˜ ๋ถ™์ด๊ธฐ

// package com.example.migrationtohilt

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

// AndroidManifest.xml์—์„œ android:name=".MyApplication" ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ ์žŠ์ง€ ๋ง๊ธฐ!
@HiltAndroidApp
class MyApplication : Application()

์ด @HiltAndroidApp ์–ด๋…ธํ…Œ์ด์…˜์€ Hilt์˜ ์•”์‹œ์  ์ฝ”๋“œ ์ƒ์„ฑ์„ ๊ฐœ์‹œ(trigger)ํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.
 

#2-6 AndroidManifest ์ˆ˜์ •

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:name=".MyApplication"
        ...>
        <activity
            ...
        </activity>
    </application>

</manifest>

์•ˆ๋“œ๋กœ์ด๋“œ ํ”„๋กœ์ ํŠธ๊ฐ€ ๊ธฐ๋ณธ Application ํด๋ž˜์Šค ๋Œ€์‹  ์ด Application ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ช…์‹œํ•œ๋‹ค. AndroidManifest์˜ <application> ํƒœ๊ทธ์˜ android:name ์†์„ฑ์— ๋ฐฉ๊ธˆ ๋งŒ๋“  Application ํด๋ž˜์Šค์˜ ์ด๋ฆ„์„ ๋„ฃ์ž.
 

#2-7 ์•ˆ๋“œ๋กœ์ด๋“œ ํด๋ž˜์Šค์— @AndroidEntryPoint ์–ด๋…ธํ…Œ์ด์…˜ ๋ถ™์ด๊ธฐ

// package com.example.migrationtohilt

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var car: Car

    override fun onCreate(savedState: Bundle?) {
        super.onCreate(savedState)
        setContentView(R.layout.activity_main)
/*
        val crankshaft = Crankshaft()
        val cylinder = Cylinder()
        val piston = Piston(crankshaft, cylinder)
        val engine = Engine(piston)
        val airbag = Airbag()
        val battery = Battery()

        val car = Car(engine, airbag, battery)
*/

//      DaggerCarComponent.create().inject(this)

        car.startCar()
    }
}

์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์„ ์•ˆ๋“œ๋กœ์ด๋“œ ํด๋ž˜์Šค์—, ์ด ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ์—๋Š” MainActivity์— @AndroidEntryPoint ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ด๋‹ค. ์ด ์–ด๋…ธํ…Œ์ด์…˜์€ Hilt๋กœ๋ถ€ํ„ฐ ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›์„ ํด๋ž˜์Šค๋ฅผ ๋ช…์‹œํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๋˜, ์ด ์–ด๋…ธํ…Œ์ด์…˜์€ ์žฌ๊ท€์ ์œผ๋กœ ๋ถ™์—ฌ์•ผํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์–ด๋–ค Fragment์— @AndroidEntryPoint๋กœ ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋ ค๋ฉด, ํ•ด๋‹น Fragment๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  Activity์—๋„ @AndroidEntryPoint ์–ด๋…ธํ…Œ์ด์…˜์˜ ๋ถ€์ฐฉ์ด ์š”๊ตฌ๋œ๋‹ค. DaggerCarComponent.create().inject(this)๋„ ์‚ญ์ œํ•œ๋‹ค. ์ด ๋ถ€๋ถ„์€ Hilt์—์„œ ์•”์‹œ์ ์œผ๋กœ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฆ‰, @Inject๊ฐ€ ๋ถ™์€ ํ•„๋“œ(์ฝ”ํ‹€๋ฆฐ์ด๋‹ˆ๊นŒ ๋” ์ •ํ™•ํžˆ ๋งํ•˜๋ฉด ํ”„๋กœํผํ‹ฐ)์— Hilt๊ฐ€ ์•Œ์•„์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ํ• ๋‹นํ•œ๋‹ค.
 

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

Crankshaft is ready
Cylinder is ready
Piston is ready
Engine is ready
Airbag is ready
Battery is ready
Car is ready

 

#3 Hilt ์‚ฌ์šฉํ•˜๊ธฐ - @Module๊ณผ @Provides

#3-1 ๊ฐœ์š”

 

[Android] Dagger2 - @Provides

#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

kenel.tistory.com

์œ„ ๊ฒŒ์‹œ๊ธ€์ฒ˜๋Ÿผ, Hilt์—์„œ @Module ๋ฐ @Provides๋ฅผ ์‚ฌ์šฉํ•ด๋ณธ๋‹ค. ์œ„ ๊ฒŒ์‹œ๊ธ€์—์„œ ๋‚˜์˜ค๋“ฏ, @Provides๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์˜์กด์„ฑ์ธ ํด๋ž˜์Šค๋ฅผ ๊ฑด๋“ค ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ๋‹ค. Airbag ๋ฐ Battery๊ฐ€ Stringํ˜• ์˜์กด์„ฑ์„ ์š”๊ตฌํ•˜๊ฒŒ ๋งŒ๋“ค์–ด๋ณธ๋‹ค. ๊ทธ๋ƒฅ ์œ„ ๊ฒŒ์‹œ๊ธ€์˜ ๋‚ด์šฉ์„ Hilt๋กœ ๋˜‘๊ฐ™์ด ์žฌํ˜„ํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.
 

#3-2 Airbag ํด๋ž˜์Šค ์ˆ˜์ •

// package com.example.migrationtohilt

import android.util.Log
import javax.inject.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}")
    }
}

 

#3-3 Battery ํด๋ž˜์Šค ์ˆ˜์ •

// package com.example.migrationtohilt

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

class Battery @Inject constructor(@Named("Battery") 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}")
    }
}

 

#3-4 Module ์ƒ์„ฑ ๋ฐ @InstallIn ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•œ ์ปดํฌ๋„ŒํŠธ ์ง€์ •

// package com.example.migrationtohilt

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Named

@Module
@InstallIn(SingletonComponent::class)
class MyModule {

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

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

์ฝ”๋“œ๋Š” Dagger์—์„œ์™€ ๊ฑฐ์˜ ๊ฐ™์œผ๋‚˜, @InstallIn์ด๋ผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์˜ ์œ ๋ฌด๋ผ๋Š” ์ฐจ์ด์ ์ด ์กด์žฌํ•œ๋‹ค. #2-4์—์„œ ๋งํ–ˆ๋“ฏ, Hilt๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ '๋งŒ๋“œ๋Š”' ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, '์„ ํƒํ•˜๋Š”' ๊ฒƒ์ด๋ฏ€๋กœ @Component ์–ด๋…ธํ…Œ์ด์…˜์ด ์—†๋‹ค. ์ด ๋•Œ ์›๋ž˜์˜ @Component์— ๋Œ€์‘๋˜๋Š” ๊ฒƒ์€ @InstallIn๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, @InstallIn์€ ํ•ด๋‹น Module์ด ์–ด๋–ค (Hilt์— built-in๋œ) ์ปดํฌ๋„ŒํŠธ์— ์„ค์น˜(Install)๋  ์ง€ ์ง€์ •ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. Dagger2์—์„œ๋Š” @Component ์–ด๋…ธํ…Œ์ด์…˜์— ์–ด๋–ค ๋ชจ๋“ˆ์„ ์“ธ ์ง€ ๋ช…์‹œํ–ˆ๋Š”๋ฐ, Hilt์—์„œ๋Š” ๋ฐ˜๋Œ€๋กœ @Module์—์„œ ์–ด๋–ค Component์— ์„ค์น˜๋  ์ง€ ๋ช…์‹œํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์ ์ด ๋Œ€๋น„๋œ๋‹ค.
 

(2025-02-01 ์ถ”๊ฐ€) @Module์€ class๊ฐ€ ์•„๋‹ˆ๋ผ object๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. Hilt ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” @Module์„ ๋‹จ์ผ ๊ฐ์ฒด(์‹ฑ๊ธ€ํ†ค)๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฆ‰, ์—ฌ๋Ÿฌ๋ฒˆ ์ธ์Šคํ„ด์Šคํ™” ๋  ๊ฒƒ์„ ์ƒ์ •ํ•˜๋Š” ํ‚ค์›Œ๋“œ์ธ class๋ฅผ ์“ธ ์ด์œ ๊ฐ€ ์—†๋‹ค. ๋ฌผ๋ก  ์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ, object ์ž๋ฆฌ์— ๋Œ€์‹  class๋ฅผ ๋‘ฌ๋„ ๋”ฑํžˆ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง„ ์•Š๋Š”๋‹ค.

 

#3-5 ์—…๋ฐ์ดํŠธ๋œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„

Airbag ๋ฐ Battery ํด๋ž˜์Šค์—์„œ Stringํ˜• ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ณ , Module๋กœ ํ•ด๋‹น Stringํ˜• ์˜์กด์„ฑ์„ @Providesํ•จ์œผ๋กœ์จ ์—…๋ฐ์ดํŠธ๋œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋‹ค.
 

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

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

 

#4 Hilt ์‚ฌ์šฉํ•˜๊ธฐ - ๋งค๊ฐœ๋ณ€์ˆ˜ ๋™์  ํ• ๋‹น

#4-1 ๊ฐœ์š” (@AssistedInject์™€ @AssistedFactory์˜ ์‚ฌ์šฉ ๋ฐฐ๊ฒฝ)

์•ž์„œ ๋งํ–ˆ๋“ฏ, Hilt๊ฐ€ Dagger2์™€ ๊ตฌ๋ณ„๋˜๋Š” ๊ฐ€์žฅ ํฐ ๋ถ€๋ถ„์€ ๋ฐ”๋กœ @Component ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๋งŒ๋“ค์ง€ ์•Š์œผ๋ฉฐ, Component ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‹จ์—์„œ ์ด๋ฏธ ์ƒ์„ฑ๋œ ์ฑ„๋กœ ํ”„๋กœ๊ทธ๋ž˜๋จธ์—๊ฒŒ ์ œ๊ณต๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์ด์ „ ๊ฒŒ์‹œ๊ธ€์—์„œ์ฒ˜๋Ÿผ Componenet.Builder๋ฅผ ํ†ตํ•ด @Module ํด๋ž˜์Šค ๋ฐ @Provides ๋ฉ”์†Œ๋“œ์— ๋™์  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

๊ทธ๋ž˜์„œ Hilt์—์„œ๋Š” ๋™์  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•œ ์˜๋„๋กœ, ๋Œ€์‹  @AssistedInject ๋ฐ @AssistedFactory ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค. @AssistedFactory ์–ด๋…ธํ…Œ์ด์…˜์˜ ์ด๋ฆ„์—์„œ ๋ณด๋“ฏ, Factory ํŒจํ„ด์„ ๊ตฌํ˜„ํ•ด์„œ Component.Builder์—์„œ ํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋น„์Šทํ•œ ๋งฅ๋ฝ์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๊ฒƒ์ด๋‹ค.
 

#4-2 @AssistedInject ๋ฐ @AssistedFactory ์–ด๋…ธํ…Œ์ด์…˜ ๋ถ™์ด๊ธฐ

// package com.example.migrationtohilt

import android.util.Log
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject

class Car @AssistedInject constructor(
    @Assisted private val engine: Engine,
    private val airbag: Airbag,
    private val battery: Battery
) {
    fun startCar() {
        engine.startEngine()
        airbag.startAirbag()
        battery.startBattery()
        Log.i("interfacer_han", "${this::class.simpleName} is ready")
    }

    @AssistedFactory
    fun interface Factory {
        fun create(engine: Engine): Car
    }
}

ํ”ผ์น˜๋ชปํ•  ์‚ฌ์ •์œผ๋กœ, Car ํด๋ž˜์Šค์˜ ์˜์กด์„ฑ ์ค‘ ํ•˜๋‚˜์ธ Engine ํด๋ž˜์Šค๋ฅผ ๋ฐ˜๋“œ์‹œ ๋Ÿฐํƒ€์ž„ ์ค‘์— ๋™์ ์œผ๋กœ ํ• ๋‹นํ•ด์•ผ๋˜๋Š” ์ƒํ™ฉ์ด ์ƒ๊ฒผ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ์˜์กด์„ฑ๋“ค ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋™์  ํ• ๋‹น์ด ์š”๊ตฌ๋˜๋ฉด ์ƒ์„ฑ์ž์— ๋ถ™์€ @Inject ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ต์งธ๋กœ @AssistedInject๋กœ ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์—, ๋™์  ํ• ๋‹น์ด ์š”๊ตฌ๋˜๋Š” ์˜์กด์„ฑ์—๋Š” @Assisted ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€๋กœ ๋ถ™์ธ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํด๋ž˜์Šค ๋‚ด๋ถ€์— Hilt๊ฐ€ Factory ํŒจํ„ด ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก @AsssistedFactory ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ SAM ํ•˜๋‚˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. interface ํ‚ค์›Œ๋“œ ์™ผ์ชฝ์˜ fun์„ ์‚ญ์ œํ•˜๊ณ  ํ‰๋ฒ”ํ•œ interface(SAM์˜ ํ›„๋ณด)๋กœ ๋‘ฌ๋„ ํฐ ์ƒ๊ด€์€ ์—†๋‹ค. ์–ด๋А ์ชฝ์ด๋“  ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ๋Š” ์ž˜ ๋œ๋‹ค.
 

#4-3 ์—…๋ฐ์ดํŠธ๋œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„

#4-2์˜ ์ฝ”๋“œ ์ˆ˜์ •์œผ๋กœ ์ธํ•ด ์—…๋ฐ์ดํŠธ๋œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋‹ค. @AssistedInject๋Š” Hilt๊ฐ€ ๊ทธ๋ ค๋‚ด๋Š” ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ถ„๋ฆฌ์‹œํ‚จ๋‹ค. ์ฆ‰, Car์™€ Engine์€ ์„œ๋กœ ๋‹ค๋ฅธ 2๊ฐœ์˜ ๊ทธ๋ž˜ํ”„์— ์†ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด ๋„์‹๋„๋ฅผ ๊ทธ๋ฆฌ๋‹ˆ, @Assisted์˜ ์˜๋ฏธ๊ฐ€ ์ œ๋Œ€๋กœ ๋ณด์ธ๋‹ค. ๋ฐ”๋กœ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๋„์™€์ฃผ์–ด์•ผ(Assist)ํ•˜๋Š” ์˜์กด์„ฑ ์ฃผ์ž…์ด๋ผ๋Š” ์˜๋ฏธ ๋ง์ด๋‹ค.
 

#4-4 MainActivity ์ˆ˜์ •

// package com.example.migrationtohilt

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    lateinit var car: Car

    @Inject
    lateinit var carFactory: Car.Factory

    @Inject
    lateinit var engine: Engine

    override fun onCreate(savedState: Bundle?) {
        super.onCreate(savedState)
        setContentView(R.layout.activity_main)

        car = carFactory.create(engine) // ๋Ÿฐํƒ€์ž„ ๋•Œ Engine ๊ฐ์ฒด ์ฃผ์ž…
        car.startCar()
    }
}

Car ํด๋ž˜์Šค ๋Œ€์‹  Car.Factory ํด๋ž˜์Šค๋ฅผ Hilt๋กœ๋ถ€ํ„ฐ ์ฃผ์ž…๋ฐ›๋Š”๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ๋ฐฉ๊ธˆ Car ์†์— ์ •์˜ํ–ˆ๋˜ interface๋ฅผ Hilt๊ฐ€ ์•Œ์•„์„œ ํด๋ž˜์Šค๋กœ์„œ ๊ตฌํ˜„ํ•ด๋†“์€ ๊ฒƒ์ด๋‹ค. ์ด ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๋Ÿฐํƒ€์ž„ ์ค‘ ๋™์  ํ• ๋‹น์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
 

#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

#3์˜ ์ˆ˜์ • ์‚ฌํ•ญ๋„ ๊ฐ™์ด ๋…น์—ฌ๋ƒˆ๊ธฐ ๋•Œ๋ฌธ์—, "Airbag made by KENEL" ๋ฐ "Battery made by TISTORY"๋ผ๋Š” ๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋„ ๋ณด์ธ๋‹ค.
 

#5 Hilt ์‚ฌ์šฉํ•˜๊ธฐ - ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด ์ฃผ์ž…

#5-1 ๊ฐœ์š”

 

[Android] Dagger2 - ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด ์ฃผ์ž… (@Binds)

#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

kenel.tistory.com

์œ„ ๊ฒŒ์‹œ๊ธ€์ฒ˜๋Ÿผ Hilt์—์„œ๋„ @Provides ๋˜๋Š” @Binds ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ฌ๋ผ์ง€๋Š” ๊ฒŒ Component ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ @InstallIn ์–ด๋…ธํ…Œ์ด์…˜ ์™ธ์—๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์—, ์„ค๋ช… ์—†์ด ์ฝ”๋“œ ์œ„์ฃผ๋กœ ๋น ๋ฅด๊ฒŒ ๋„˜๊ธด๋‹ค. ์ด ๊ฒŒ์‹œ๊ธ€์—์„œ๋Š” Piston ํด๋ž˜์Šค๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ „ํ™˜ํ•˜๊ณ  ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณธ๋‹ค.
 

#5-2 Piston ํด๋ž˜์Šค๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ „ํ™˜

// package com.example.migrationtohilt

interface Piston {
    fun startPiston()
}

 

#5-3 Piston ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด TitaniumPiston ํด๋ž˜์Šค ์ƒ์„ฑ

// package com.example.migrationtohilt

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

class TitaniumPiston @Inject constructor(
    private val crankshaft: Crankshaft,
    private val cylinder: Cylinder
) : Piston {
    override fun startPiston() {
        crankshaft.startCrankshaft()
        cylinder.startCylinder()
        Log.i("interfacer_han", "${this::class.simpleName} is ready")
    }
}

 

#5-4 Piston์˜ ๊ตฌํ˜„์ฒด๋ฅผ @Providesํ•˜๊ฑฐ๋‚˜ @Bindsํ•˜๊ธฐ ์œ„ํ•œ PistonModule

// package com.example.migrationtohilt

import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

/*

// @Provides๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ
@Module
@InstallIn(SingletonComponent::class)
class PistonModule {

    @Provides
    fun providesTitaniumPiston(titaniumPiston: TitaniumPiston) : Piston {
        return titaniumPiston
    }
}

*/

// @Binds๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ
@Module
@InstallIn(SingletonComponent::class)
abstract class PistonModule {

    @Binds
    abstract fun providesTitaniumPiston(titaniumPiston: TitaniumPiston): Piston
}

์ผ๋ฐ˜ ํด๋ž˜์Šค PistonModule๊ณผ @Provides์˜ ์กฐํ•ฉ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ์ถ”์ƒ ํด๋ž˜์Šค PistonModule๊ณผ @Binds์˜ ์กฐํ•ฉ์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด์˜ ์ฃผ์ž…์€ ํ›„์ž์˜ ๋ฐฉ์‹์ด ์ผ๋ฐ˜์ ์ด๋‹ค. 
 

#5-5 ์—…๋ฐ์ดํŠธ๋œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„

 

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

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

#3์˜ ์ˆ˜์ • ์‚ฌํ•ญ๋„ ๊ฐ™์ด ๋…น์—ฌ๋ƒˆ๊ธฐ ๋•Œ๋ฌธ์—, "Airbag made by KENEL" ๋ฐ "Battery made by TISTORY"๋ผ๋Š” ๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋„ ๋ณด์ธ๋‹ค.
 

#6 ์š”์•ฝ

Hilt๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์–ป๋Š” ์ด์ ์€, ์ถ”์ƒํ™” ๊ณ„์ธต์„ ์ด์šฉํ•ด์„œ ์–ป๋Š” ์ด์ ๊ณผ ๋™์ผํ•˜๋‹ค.
 

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

#7-1 ๊นƒํ—ˆ๋ธŒ ๋งํฌ

 

android-practice/dagger2/MigrationToHilt at master · Kanmanemone/android-practice

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

github.com

#2 ~ #5์˜ ๋ชจ๋“  ์ˆ˜์ •์‚ฌํ•ญ์„ ์ „๋ถ€ ์ ์šฉํ–ˆ๋‹ค.
 

#7-2 ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„

#2 ~ #5 ์˜ ๋ชจ๋“  ์ˆ˜์ •์‚ฌํ•ญ์ด ์ „๋ถ€ ์ ์šฉ๋œ ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋‹ค.