안드로이드 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() 생성해줘야 합니다.