Hilt 란?
Hilt 는 Android Jetpack 에서 지원하는 DI ( Dependency Injection ) Library 로 Dagger 를 기반으로 빌드되었다고 합니다.
하지만 Dagger 는 러닝 커브가 매우 높은 편이고(쉽게 말하면 어렵다...)
그걸 Android 쪽에서도 인지하고 만든게 Hilt 입니다. 그래서 Dagger 보단 구현적인 측면에선 많이 쉽습니다(개인적인 의견입니다.)
DI 에 대한 개념이 잘 잡히지 않으신다면 우선 아래 링크를 보고 오시면 될 것 같습니다.
Android의 종속 항목 삽입 | Android 개발자 | Android Developers
Android의 종속 항목 삽입 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 종속 항목 삽입(DI)은 프로그래밍에 널리 사용되는 기법으로, Android 개발에 적합합니
developer.android.com
아래는 Hilt 를 프로젝트에서 사용할 경우 gradle 에서 세팅해야 할 항목들입니다.
Project Level 의 build.gradle 입니다.
buildscript {
dependencies {
classpath ("com.google.dagger:hilt-android-gradle-plugin:2.46.1")
}
}
plugins {
// id("com.android.application") version "8.2.1" apply false
// id("com.android.library") version "8.2.1" apply false
id("org.jetbrains.kotlin.android") version "1.8.10" apply false
}
module level 의 build.gradle 입니다.
plugins {
// id("com.android.application")
// id("org.jetbrains.kotlin.android")
id ("org.jetbrains.kotlin.kapt")
id ("dagger.hilt.android.plugin")
}
dependencies {
// ...
implementation ("com.google.dagger:hilt-android:2.46.1")
kapt ("com.google.dagger:hilt-compiler:2.46.1")
// ...
}
위의 두 코드 블럭에서 주석처리되지 않은 부분들을 Gradle 에 추가해주고
현재 어플리케이션이 HiltAndroidApp 임을 annotation 을 통해 명시해줍니다.
@HiltAndroidApp
class MyApplication : Application(){
override fun onCreate() {
super.onCreate()
}
}
이런식으로 Application 을 상속받는 class 를 생성하여 annotation 을 붙여주고
<application
android:name=".MyApplication"
// ...
</application>
manifest 에서 이렇게 선언해줍니다.
오늘 예시로 사용할 소스코드는 TMDB 의 영화 검색 API 를 Hilt 를 이용해서 주입하는 과정입니다.
interface TmdbApi{
@GET("$ACTION_DISCOVER/$TYPE_SERIES?api_key=${API_KEY}")
fun getTvData(@QueryMap options: Map<String, String>): Call<BaseData<Series>>
@GET("$ACTION_DISCOVER/$TYPE_MOVIE?api_key=${API_KEY}")
fun getMovieData(@QueryMap options: Map<String, String>): Call<BaseData<Movie>>
}
그리고 이제 의존성을 주입해줄 모듈을 만들어봅시다.
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
private val loggingInterceptor = HttpLoggingInterceptor()
@Provides
@Singleton
fun provideClient(): OkHttpClient{
return OkHttpClient.Builder()
.addInterceptor(loggingInterceptor.apply {
level = HttpLoggingInterceptor.Level.BODY
}).build()
}
@Provides
@Singleton
fun provideRetrofit(client: OkHttpClient): Retrofit {
return Retrofit.Builder()
.client(client)
.baseUrl(TmdbApi.BASE_URL)
.addConverterFactory(JacksonConverterFactory.create())
.build()
}
@Provides
@Singleton
fun provideTmdb(retrofit: Retrofit): TmdbApi {
return retrofit.create(TmdbApi::class.java)
}
}
이렇게하면 아래와같이 좌측에 종속성에 관한 아이콘이 생길겁니다.
그리고 저 TmdbApi 를 이제 주입받아봅시다.
아래의 경우 종속성을 생성자에서 주입 받았습니다.
@Singleton
class VideoRepository @Inject constructor(
private val tmdbApi: TmdbApi
) {
fun getData(
queries: Map<String, String>
): BaseData<*>? {
val call= tmdbApi.getDiscoveredTvData(
queries
)
val response = call.execute()
return if (response.isSuccessful){
response.body()
}
else{
null
}
}
}
그리고 이 Repository 를 ViewModel 에서 간단하게 주입받아 사용할 수 있습니다.
@HiltViewModel
class VideoViewModel @Inject constructor(
private val repository: VideoRepository
) : ViewModel(){
private val mVideoData = MutableLiveData<BaseData<*>>()
val data: LiveData<BaseData<*>>
get() {
return mVideoData
}
suspend fun setData(options: Map<String, String>){
mVideoData.postValue(
repository.getData(
queries = options
)
)
}
}
기존에 ViewModelFactory 를 상속받은 class 의 메서드를 수정해서 사용하던 것 보다 훨씬 코드가 간단해졌죠.
위 코드들을 간단하게 테스트 해봅시다
val viewModel = ViewModelProvider(this)[VideoViewModel::class.java]
viewModel.data.observe(this){
println(it)
}
val options = Options.discoverVideo(
page = 1,
networkId = TmdbConfigs.Tving.id
)
CoroutineScope(Dispatchers.IO).launch {
viewModel.setData(options)
}
BaseData(page=1, results=[Series(backdropPath=/icy4p7Nb33UU2S5eHvlBcE0Dvmi.jpg, firstAirDate=2023-12-15, genreIds=[18, 10765], id=218230, name=이재, 곧 죽습니다, originCountry=[KR], originalLanguage=ko, originalName=이재, 곧 죽습니다, overview=지옥으로 떨어지기 직전의 이재가 죽음이 내린 심판에 의해 12번의 죽음과 삶을 경험하게 되는 판타지 인생 환승 드라마. 이원식 & 꿀찬의 웹툰 "이제 곧 죽습니다" 원작, popularity=200.883, posterPath=/5LwZzaFN0kmpLWuqPm6LnF4iRF2.jpg, voteAverage=8.6, voteCount=91), ... ]
제대로 동작 하는군요
'Android > Kotlin' 카테고리의 다른 글
Jetpack Compose 에서 Dialog 구현하기 (1) | 2024.02.07 |
---|---|
Jetpack Compose 에서 ProgressBar 구현하기 (0) | 2024.02.05 |
Android Kotlin 의 Enum class (1) | 2024.01.17 |
Android Exoplayer 현재 재생 중인 Stream 의 Format 확인 방법 (0) | 2024.01.12 |
Android 배워보자 Compose! -(4) (0) | 2024.01.12 |