종속성 관리를 자동화 해주는 Dagger Hilt 사용하기 – @Composable/Android
가장 먼저 해야할 일은, 라이브러리를 추가해주는 것입니다. 꼭 버전을 통일해야만 한다!
나는 2.51.1 버전으로 통일했다.
라이브러리 설치하기
// <프로젝트폴더>/build.gradle.ktx
buildscript {
dependencies {
classpath(libs.google.services)
// 추가한 부분
classpath("com.google.dagger:hilt-android-gradle-plugin:2.51.1")
}
}
plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.jetbrainsKotlinAndroid) apply false
}
이어서 프로젝트쪽 설정에도 추가한다.
// <프로젝트폴더>/app/build.gradle.ktx
plugins {
...
// 추가한 부분
kotlin("kapt")
id("dagger.hilt.android.plugin")
}
android {
...
// 갑자기 Lint 에러가 나서 추가한 부분
composeOptions {
checkReleaseBuilds = false
abortOnError = false
}
}
dependencies {
...
// 추가한 부분
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
implementation("com.google.dagger:hilt-android:2.51.1")
kapt("com.google.dagger:hilt-android-compiler:2.51.1")
}
// 추가한 부분
kapt {
correctErrorTypes = true
}
완벽하다! 여기까지가 패키지를 설치하는 방법이다!
이어서 나만의 종속성 모듈을 만들 차례다!
우선 그럴듯 하게 DiModule 이라고 파일을 하나 만든다.
내 취향이 아니다. GPT가 멋지게 지어준거다.
package com.zucchini.dreamstore.di
@Module
@InstallIn(SingletonComponent::class)
object DiModule {
@Provides
@Singleton
fun provideMyClass(): MyClass {
return MyClass()
}
}
이렇게 MyClass 타입을 제공하는 함수를 하나 만들어 주면, 모든 @HiltViewModel 어노테이션과 함께 작성된 뷰 모델에서 사용할 수 있다.
@HiltViewModel
class MyViewModel @Inject constructor(
@ApplicationContext private val context: Context,
private val myClass: MyClass,
) : ViewModel() {
...
}
이렇게 Hilt는 따로 뷰모델 생성자에 무언가 집어넣지 않아도 알아서 객체를 대입해주기 때문에, 정말 편리하게 뷰 모델을 이용할 수 있게 되는 것이다.
여기에 공유 가능한 뷰 모델을 다음과같이 선언한다면, 더더욱 독립적이고 유용한 코드를 작성할 수 있다.
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val myViewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme {
Surface(
modifier = Modifier
.fillMaxSize()
.background(Color.White),
) {
// 이렇게 만들어 주면 뷰 모델을 어떤 화면이든 가져가서 사용할 수 있다!
CompositionLocalProvider(
LocalMyViewModel provides myViewModel,
) {
AppNavigation()
}
}
}
}
}
}
단순하게 이렇게 가져올 수 있는 것이다!
@Composable
fun MyScreen(
navController: NavHostController,
) {
val viewModel = LocalMyViewModel.current
...
}
그런데 여기서 중요한 것이 있다! 컨텍스트를 이용하는 클래스라면 어떻게 해야 할까?
아래의 코드와 같이 provideContext
함수를 만들어서 컨텍스트 또한 제공을 해 주어야만 한다. 그래야 컨텍스트를 별도로 주입하지 않아도 Hilt를 사용하여 context 객체를 편리하게 사용할 수 있다.
@Module
@InstallIn(SingletonComponent::class)
object DiModule {
@Provides
@Singleton
fun provideSocialSignInManager(@ApplicationContext context: Context): SocialSignInManager {
return SocialSignInManager(context)
}
@Provides
@Singleton
fun provideContext(@ApplicationContext context: Context): Context {
return context
}
}