본문 바로가기
Android

[Android] 쉽고 간편한 Dagger Hilt를 사용해 보자!

by 안솝우화 2021. 12. 29.
반응형

안녕하세요, 오늘은 Hilt에 대해 알아보려 합니다.

우선 알아보기 전에 의존성 주입이라는 개념에 대해 이해해야 하는데요

저의 이전 글을 참고하거나 구글링을 통해 개념을 조금 파악하시기 바랍니다

2021.08.24 - [Android Studio/Dependency] - 의존성 주입이란?

 

의존성 주입이란?

의존성(종속성) 이란? 위에 사진을 보면 ComputerClass가 CpuClass를 이용하고 있는 것을 볼 수 있습니다 여기서 종속성이 발생하는데 종속성이란 두 클래스가 상호 종속될 때 코드 기반에서 일어나는

asuhdevstory.tistory.com

우선 Dagger2라는 의존성 주입 라이브러리는 러닝 커브가 높고 어렵습니다. 하지만 이런 Dagger2를 쉽게 사용할 수 있게 나온 것이 바로 Dagger Hilt입니다

Hilt는 여러분이 생각하는 것 그 이상으로 더 간단하고 이 글 한 개로도 충분이 사용하실 수 있을 겁니다

이 글에서는 간단하게 GithubApi를 Retrofit을 이용하여 호출하는 예시를 보여드립니다

깃허브 코드는 아래 링크에 있습니다

https://github.com/ParkSangSun1/Github_RxKotlin

 

GitHub - ParkSangSun1/Github_RxKotlin: MVVM, RxKotlin을 사용한 Github 사용자 Repository 확인 예제

MVVM, RxKotlin을 사용한 Github 사용자 Repository 확인 예제. Contribute to ParkSangSun1/Github_RxKotlin development by creating an account on GitHub.

github.com

 

 

@HiltAndroidApp

App.kt

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

@HiltAndroidApp
class App : Application() {
    private var instance: App? = null

    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}

먼저 Hilt를 사용하기 위해선 @HiltAndroidApp 어노테이션을 앱 시작할 때 실행시켜줘야 합니다. 때문에 Application()을 상속받은 App이라는 클래스에 어노테이션을 선언해주고 이 클래스를 AndroidManifest.xml에서 name으로 설정해줍니다

 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.pss.github_rxkotlin">
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:name="com.pss.github_rxkotlin.di.App"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Quick_Setup">
        <activity
            android:name="com.pss.github_rxkotlin.view.MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

이렇게 하면 준비운동은 끝이 납니다! 참 쉽죠?

 

 

@Module, @InstallIn(SingletonComponent::class), @Provides

외부 라이브러리 (Retrofit, Okhttp 등)는 Hilt가 어떻게 객체를 생성해야 하는지 방법을 모르기 때문은 @Modules를 사용해 우리가 알려줘야 합니다

@InstallIn(SingletonComponent::class)는 해당 모듈을 싱글턴으로 사용하겠다는 의미입니다

그러고 나서 클래스 안의 함수 앞에 @Provides, @Singletion 어노테이션을 붙여줍니다

 

NetworkModule.kt

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

    @Provides
    @Singleton
    fun provideHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .readTimeout(10, TimeUnit.SECONDS)
            .connectTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(15, TimeUnit.SECONDS)
            .addInterceptor(getLoggingInterceptor())
            .build()
    }

    @Singleton
    @Provides
    fun provideRetrofitInstance(
        okHttpClient: OkHttpClient,
        gsonConverterFactory: GsonConverterFactory
    ): Retrofit {
        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .client(provideHttpClient())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(gsonConverterFactory)
            .build()
    }

    @Provides
    @Singleton
    fun provideConverterFactory(): GsonConverterFactory {
        return GsonConverterFactory.create()
    }


    private fun getLoggingInterceptor(): HttpLoggingInterceptor =
        HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }

    @Provides
    @Singleton
    fun provideGithubApiService(retrofit: Retrofit): GithubApi {
        return retrofit.create(GithubApi::class.java)
    }
}

Retrofit을 사용하기 위한 NetworkModule입니다

 

RepositoryModule.kt

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

    @Provides
    @Singleton
    fun provideMainRepository(
        githubApi: GithubApi
    ) = MainRepository(githubApi)
}

ViewModel에 Repository를 주입해서 사용하기 위한 Module

이곳에서 위에 선언한 NetworkModule의 provideGithubApiService함수를 이용해 GithubApi 의존성 주입을 받습니다

 

 

@HiltViewModel, @Inject

@Inject은 의존성 주입을 받겠다는 의미입니다. 사용할 때는 반드시 constructor()과 함께 사용해야 합니다.

위에서 RepositoryModule를 만들어주었고 반환형이 MainRepository인 provideMainRepository 함수를 선언했기 때문에 의존성 주입이 가능하게 됩니다 

일반적인 클래스에서는 이렇게 @Inject를 사용해 의존성 주입을 받을 수 있지만 ViewModel에서는 @HiltViewModel이라는 어노테이션을 사용해야 합니다. 하지만 정말 이 한 줄만 추가로 사용하면 끝나기 때문에 그렇게 어렵지 않다는 점!

@HiltViewModel
class MainViewModel @Inject constructor(
    private val mainRepository: MainRepository
) : ViewModel() {

    fun getUserInfo(owner: String) = mainRepository.getUserInfo(owner)
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.io())
        .subscribe({ items ->
            items.forEach { println(it) }
        }, { e ->
            println(e.toString())
        })

}

 

 

@AndroidEntryPoint

ViewModel까지 만들었다면 이제 이것을 사용할 activity가 필요할 겁니다

이때 ViewModel을 사용하는 activity에 @AndroidEntryPoint를 이용해 사용할 수 있습니다

Fragment에서 사용한다면 Fragment가 붙어있는 activity에 @AndroidEntryPoint를 붙여 사용할 수 있습니다

@AndroidEntryPoint
class MainActivity : BaseActivity<ActivityMainBinding>(R.layout.activity_main) {
    private val mainViewModel by viewModels<MainViewModel>()


    override fun init() {
        binding.activity = this
    }

    fun clickSearchBtn(view: View){
        mainViewModel.getUserInfo(binding.name.text.toString())
    }
}

이렇게만 해줘도 Hilt를 이용해 쉽게 GithubApi를 호출해볼 수 있습니다!!

 

추가로

안드로이드 개발에 대한 질문과 정보 등을 공유 및 소통하는 채팅방입니다

https://open.kakao.com/o/gG5PueVd

반응형