Bookmark profile

가장 먼저 해야할 일은, 라이브러리를 추가해주는 것입니다. 꼭 버전을 통일해야만 한다!

나는 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
    }
}