본문 바로가기

Android Library

[Android Library] Hilt (2) - 기본 사용법

안녕하세요.

Hilt를 사용해서 코드를 리펙토링 해보겠습니다.


Gradle 설정

Hilt를 사용하려면 Gradle 설정을 해줘야 합니다.

 

build.gradle (Project 수준)

(버전은 공식문서를 참고해주세요)

plugins {
    ...

    id("com.google.dagger.hilt.android") version "2.44" apply false
}

build.gradle (App 수준)

plugins {
    ...

    id("org.jetbrains.kotlin.kapt")
    id("com.google.dagger.hilt.android")
}

...

dependencies {
    ...

    implementation("com.google.dagger:hilt-android:2.44")
    kapt("com.google.dagger:hilt-android-compiler:2.44")
}

kapt {
    correctErrorTypes = true
}

HiltAndroidApp

Hilt를 사용하여 안드로이드 어플리케이션을 초기화하는데 사용됩니다.

Hilt를 통한 전체 어플리케이션 범위에서 주입 가능한 컴포넌트 및 의존성을 설정하기 위해 사용됩니다.

 

BasicApplication.kt

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

@HiltAndroidApp
class BasicApplication : Application() {
}

Manifest

...

<application
        android:name=".BasicApplication"
				...

AndroidEntryPoint

Hilt에서 안드로이드 컴포넌트에 의존성 주입을 설정하기 위해 사용됩니다.

ex) Activity, Frament, Service, BroadcastReceiver, ContentProvider 등)

아래에서 제시하는 코드들은 아직 의존성 주입이 사용되지 않은 객체들입니다.
이를 Hilt를 통해 리펙토링 해볼 예정입니다.

 

MainActivity.kt

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    lateinit var house : House

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

        house = House()
        house.introduce()
        house.getPhoneControl()
    }
}

House.kt

class House {
    val phone1 = PhoneA()
    val phone2 = PhoneB()

    fun introduce() {
        Log.i(TAG.TAG_HILT, "I'm house")
    }

    fun getPhoneControl() {
        phone1.getControl()
        phone2.getControl()
    }
}

Phone.kt

interface Phone {
    fun getControl()
}

PhoneA.kt

class PhoneA : Phone {
    override fun getControl() {
        Log.i(TAG.TAG_HILT, "getting a control using Phone A")
    }
}

PhoneB.kt

class PhoneB : Phone {
    override fun getControl() {
        Log.i(TAG.TAG_HILT, "getting a control using Phone B")
    }
}

Inject

Hilt가 의존성을 자동으로 인식하고 주입할수 있도록 도와주는 어노테이션 입니다.

주입 가능한 필드, 생성자 및 메서드에 적용될 수 있습니다.

 

MainActivity.kt

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    @Inject lateinit var house: House

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

        house.introduce()
        house.getPhoneControl()
    }
}

House.kt

생성자 주입을 이용했습니다.

class House @Inject constructor() {
    val phone1 = PhoneA()
    val phone2 = PhoneB()

    fun introduce() {
        Log.i(TAG.TAG_HILT, "I'm house")
    }

    fun getPhoneControl() {
        phone1.getControl()
        phone2.getControl()
    }
}

 

MainActivity <-> House 사이의 리펙토링이 완료됐습니다.

House <-> Phone 사이의 리펙토링도 진행해보겠습니다.


Module

어떤 클래스인지 구분하기 위해 사용합니다.

(PhoneA 클래스인지, PhoneB 클래스인지)

 

@InstallIn 어노테이션은 해당 모듈이 어떤 범위에서 쓰이는지를 나타냅니다.

  • @InstallIn(SingletonComponent.class): 애플리케이션 수명 주기 동안 의존성을 설정
  • @InstallIn(ActivityComponent.class): 액티비티 수준의 컴포넌트. 액티비티의 수명 주기 동안 의존성을 설정
  • @InstallIn(ViewModelComponent.class): Android ViewModel에 연결된 컴포넌트. ViewModels에 의존성을 설정
  • @InstallIn(FragmentComponent.class): 프래그먼트 수준의 컴포넌트. 프래그먼트 수명 주기 동안 유지되는 의존성을 설정

 

PhoneModule.kt

(@Binds 어노테이션은 바로 아래 문단에서 설명하겠습니다.)

@Module
@InstallIn(ActivityComponent::class)
abstract class PhoneModule {

    @PhoneAQualifier
    @Binds
    abstract fun PhoneAImpl(phone_A: PhoneA) : Phone

    @PhoneBQualifier
    @Binds
    abstract fun PhoneBImpl(phone_B: PhoneB) : Phone
}

@Qualifier
annotation class PhoneAQualifier

@Qualifier
annotation class PhoneBQualifier

Binds

추상 메서드를 구체적인 구현체로 연결할 때 사용됩니다.

주로 인터페이스 또는 추상 클래스에 대한 구현체를 제공할 때 사용됩니다.

 

House.kt

class House @Inject constructor() {
    @PhoneAQualifier
    @Inject lateinit var phone1: Phone

    @PhoneBQualifier
    @Inject lateinit var phone2: Phone

    fun introduce() {
        Log.i(TAG.TAG_HILT, "I'm house")
    }

    fun getPhoneControl() {
        phone1.getControl()
        phone2.getControl()
    }
}

Phone.kt

interface Phone {
    fun getControl()
}

PhoneA.kt

class PhoneA @Inject constructor() : Phone {
    override fun getControl() {
        Log.i(TAG.TAG_HILT, "getting a control using Phone A")
    }
}

PhoneB.kt

class PhoneB @Inject constructor() :Phone {
    override fun getControl() {
        Log.i(TAG.TAG_HILT, "getting a control using Phone B")
    }
}

 

House <-> Phone 사이의 리펙토링이 완료됐습니다.

 

위와 같은 코드를 치면, 안드로이드에서는 아래 클래스들을 만들어서 위와 같은 코드가 돌아가도록 만들어줍니다.


Provides

외부 라이브러리에서 제공되는 경우나

빌드 패턴 등의 인스턴스를 생성해야 하는 경우에 사용합니다.

@Module
@InstallIn(ActivityComponent::class)
class AppModule {
    @Provides
    fun provideRetrofitService(): RetrofitService {
        return Retrofit.Builder()
            .baseUrl("https://~")
            .build()
            .create(RetrofitService::class.java)
    }
}

Reference

Hilt를 사용한 종속 항목 삽입  |  Android 개발자  |  Android Developers

 

Hilt를 사용한 종속 항목 삽입  |  Android 개발자  |  Android Developers

Hilt를 사용한 종속 항목 삽입 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Hilt는 프로젝트에서 종속 항목 수동 삽입을 실행하는 상용구를 줄이는 Android용

developer.android.com

Android 앱에서 Hilt 사용  |  Android 개발자  |  Android Developers

 

Android 앱에서 Hilt 사용  |  Android 개발자  |  Android Developers

이 Codelab에서는 Hilt를 사용하여 종속 항목 삽입을 실행하는 Android 앱을 빌드해 보겠습니다.

developer.android.com

힐트 Hilt 안드로이드에서 의존성 관리하기

 

힐트 Hilt 안드로이드에서 의존성 관리하기

힐트 Hilt - Android 모듈 정리 Hilt는 의존성을 추가하는 (dependency injection, di)는 라이브러리이다. ''의존''이란 한 클래스가 다른 클래스를 참고한다는 뜻인데, 개발을 하다보면 여러 클래스끼리 연결

software-creator.tistory.com

[Android] Hilt @Binds, @Providers 차이점

 

[Android] Hilt @Binds, @Providers 차이점

Android에서 의존성 주입(DI / Dependency Injection)을 도와주기 위해서 Hilt 라이브러리를 제공해 줍니다. Hilt 라이브러리를 사용하면 의존성 주입을 위해 Android 프로젝트에 컨테이너를 제공하고 수명 주

3edc.tistory.com