안드로이드 hilt 의존성 주입 라이브러리 적용 과정을 메모.

 

App 단의 Gradle에서

buildscript {
    dependencies {
        classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
    }

}

 

모듈단의 Gradle에서

apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'


dependencies {
    implementation "com.google.dagger:hilt-android:2.28-alpha"
    kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
}

kapt를 사용합니다.

 

Application을 상속받는 클래스를 하나 만들어서

@HiltAndroidApp 어노테이션을 추가합니다.

@HlitAndroidApp
class AppName : Application()

 

manifest >> application에 AppName을 설정해줍니다

    <application
        android:name="com.my.App"
        android:allowBackup="false"
        android:hardwareAccelerated="true"
        android:icon="@drawable/ic_app_icon"
        android:label="${appName}"
        android:largeHeap="true"
        android:enableOnBackInvokedCallback="true"
        android:requestLegacyExternalStorage="true"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApp"
        android:usesCleartextTraffic="true"
        tools:replace="android:label,android:theme,android:allowBackup,android:icon">

 

기본적인 세팅은 끝이 났고, 사용하면됩니다.

 

예를들어 특정 모듈에 의존성을 주입하고싶다면.

 

NetworkModule.kt

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

    @Provides
    fun provideGson(): Gson = GsonBuilder().create()

    @Provides
    fun provideGoodPharmOkHttpClient() : OkHttpClient =
        if(BuildConfig.DEBUG) { // for debug
            OkHttpClient.Builder()
                .callTimeout(30, TimeUnit.SECONDS)
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(network.RequestInterceptor())
                .addInterceptor(network.ResponseInterceptor())
                .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                .build()
        } else{
            OkHttpClient.Builder()
                .callTimeout(30, TimeUnit.SECONDS)
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(network.RequestInterceptor())
                .addInterceptor(network.ResponseInterceptor())
                .build()
        }

    @Singleton
    @Provides
    @Named("scalar")
    fun provideStringRetrofit (
        okHttpClient: OkHttpClient
    ) : Retrofit =
        Retrofit.Builder()
            .baseUrl(BuildConfig.ServerUrl)
            .addConverterFactory(ScalarsConverterFactory.create())
            .client(okHttpClient)
            .build()

    @Singleton
    @Provides
    @Named("gson")
    fun provideGoodPharmGsonRetrofit (
        okHttpClient: OkHttpClient
    ) : Retrofit =
        Retrofit.Builder()
            .baseUrl(BuildConfig.ServerUrl)
            .addConverterFactory(nullOnEmptyConverterFactory)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpClient)
            .build()

    /**
     * 응답값이 비어있는 경우 처리
     */
    private val nullOnEmptyConverterFactory = object : Converter.Factory() {
        fun converterFactory() = this
        override fun responseBodyConverter(type: Type, annotations: Array<out Annotation>, retrofit: Retrofit) = object : Converter<ResponseBody, Any?> {
            val nextResponseBodyConverter = retrofit.nextResponseBodyConverter<Any?>(converterFactory(), type, annotations)
            override fun convert(value: ResponseBody) = if (value.contentLength() != 0L) nextResponseBodyConverter.convert(value) else null
        }
    }
}

이런식으로 사용하면됩니다.

 

@Singleton 어노테이션을 사용하는 이유는 해당 모듈에 대한 싱글톤 패턴을 지키면서 인스턴스 중복생성을 막기 위함입니다.

 

 

 

Activity나 Fragment단에도 Hilt를 적용한다면.

@AndroidEntryPoint 어노테이션을 사용하면됩니다.

 

MyActivity.kt

@AndroidEntryPoint
class MyActivity : BaseActivity<ActivityMyBinding>(R.layout.activity_my) {
	
    private val myViewModel: MyViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding {
             ...
            }
	    }
}

Activity의 경우. Fragment도 동일합니다.

 

view model에 의존성을 주입하는 경우 @HiltViewModel이라는 어노테이션을 사용하면됩니다.

 

MyViewModel.kt

@HiltViewModel
class MyViewModel @Inject constructor(
    private val myUseCase: MyUseCase
): BaseViewModel() { // ViewModel 을 상속받는 베이스 클래스 입니다.

// sample live data
    private val _sampleLiveData = MutableLiveData<String>()
    val sampleLiveData: MutableLiveData<String> = _sampleLiveData

// sample code
    fun checkSample(){
        viewModelScope.launch {
            _sampleLiveData.value = myUseCase.checkSample()
        }
    }
}

생성자가 별도로 필요하지 않은 경우에도

@Inject constructor() 생성해줘야 합니다.

+ Recent posts