Hilt는 기존의 Dagger2의 과도하게 많은 annotaiton과 보일러 플레이트 코드, 매우 높은 학습곡선등의 단점들을 해소하기 위해 구글에서 제공하는 라이브러리며, 현재는 jetpack에 합류되었다.
// Dagger-Hilt
implementation "com.google.dagger:hilt-android:2.28-alpha"
kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
// Dagger-Hilt with Jetpack
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
Hilt를 사용하기 위해 의존성을 추가한다. viewModel 패턴을 사용하지 않는다면 아래의 두줄은 필요없다.
@HiltAndroidApp
class MyApplication : Application()
이전에는 직접 의존성을 추가해줬지만, 이제는 Hilt를 사용해야 하므로 기존의 의존성 주입 코드는 모두 제거하였다.
Hilt를 사용하기위해선 Application을 상속받는 클래스에서 HiltAndroidApp annotation을 추가해야한다.
@AndroidEntryPoint
class MainActivity
의존성 주입을 받을 컴포턴트에 AndroidEntryPoint annotation을 추가한다. 이를 사용할 수 있는 타입은 다음과 같다.
- Activity
- Fragment
- View
- Service
- BroadcastReceiver
class MainViewModel @ViewModelInject constructor()
viewModel을 사용할 때에는 위와같이 ViewModelInject annotation을 선언하고, constructor를 작성, 그 안에 의존성을 주입한다.
@Module
@InstallIn(ApplicationComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideService(): ServiceApi {
val retrofit = Retrofit.Builder()
.baseUrl(ServiceApi.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
return retrofit.create(ServiceApi::class.java)
}
}
Hilt에서 의존성을 주입하기 위해선 Module을 작성해야한다.
InstallIn annotation을 통해 어떤 component에 모듈을 사용할것인지를 정해야한다. applicationComponent는 내부적으로 application 클래스를 사용한다.
class SearchRemoteDataSourceImpl @Inject constructor (private val service: ServiceApi)
앞서 말했듯 inject 어노테이션을 선언하고 이런식으로 constructor에 의존성을 주입하면 된다.
@Module
@InstallIn(ApplicationComponent::class)
abstract class RepoBindModule {
@Binds
abstract fun bindSearchRemote(remoteDataSource: SearchRemoteDataSourceImpl) : SearchRemoteDataSource
@Binds
abstract fun bindSearchRepo(searchRepo: SearchRepositoryImpl) : SearchRepository
}
binds 어노테이션을 사용하여 추상화된 interface와 구현체를 연결해야한다. (따로 추상화/구현을 분리하지 않았다면 생략)
@Module
@InstallIn(ApplicationComponent::class)
object RepoModule {
@Singleton
@Provides
fun provideSearchRemoteDataSource(serviceApi: ServiceApi) = SearchRemoteDataSourceImpl(serviceApi)
@Singleton
@Provides
fun provideSearchRepo(searchRemoteDataSource: SearchRemoteDataSource) = SearchRepositoryImpl(searchRemoteDataSource)
}
Retrofit service와 같은 방식으로 나머지에도 마저 의존성 주입을 해주었다.
(공식 디벨로퍼 가이드에도 마찬가지로 obejct로 선언했기 때문에 사실 이미 싱글톤으로 구현되는데 굳이 Singleton 어노테이션을 추가해야하는 이유를 모르겠다. 실제로 해당 어노테이션을 지워도 해쉬코드를 찍어보면 전부 하나의 객체임을 알 수 있다.)
Reference:
taehyungk.github.io/posts/android-DI-Hilt/
[DI] Hilt 로 Dagger 를 쉽게 쓰자 !
Hilt
taehyungk.github.io
github.com/sberoch/RickAndMorty-AndroidArchitectureSample
sberoch/RickAndMorty-AndroidArchitectureSample
A Rick And Morty simple app to show one approach to using some of the best practices in Android Development. - sberoch/RickAndMorty-AndroidArchitectureSample
github.com
전체 코드:
github.com/YeseopLee/ArchitectureStudy/tree/mvvm+hilt
YeseopLee/ArchitectureStudy
Contribute to YeseopLee/ArchitectureStudy development by creating an account on GitHub.
github.com
마치며
오리지널 Dagger2는 아직 공부중이지만, Hilt를 사용해보면 정말로 놀라울정도로 많이 간소해졌음을 알 수 있었다.
그러나 모든 로직을 어노테이션으로만 구현하는 형식이다보니, 로직이 한눈에 들어오지 않는다는 단점이 있다.(고 하는데 사실 기존의 dagger2를 익숙하게 사용하지 못하는 입장에서는 잘 와닿지 않는 이야기..)
나중에 살펴보겠지만, 코틀린을 위해 편하게 사용할 수 있는 의존성 주입 라이브러리인 Koin과는 다르게 빌드시에 에러를 뱉어주기때문에 더 안정적으로 사용할 수 있다는 장점이 있다.
+ 번외)
detailViewModel = ViewModelProvider(this, viewModelFactory { DetailViewModel(owner, name) }).get(DetailViewModel::class.java)
protected inline fun <VM : ViewModel> viewModelFactory(crossinline f: () -> VM) =
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(aClass: Class<T>): T = f() as T
}
기존의 코드는 위처럼 factory를 통해 recyclerview에서 아이템 클릭시 bundle을 이용하여 데이터를 전달하였다.
그러나 이경우 사실 데이터가 view를 통해 다시 viewModel에 전달되는 방식이라 생각되는데, view와 viewmodel의 관심사 분리 라는 측면에서 좋지 않은 방식이라 생각하여, sharedPreference를 사용하였다.
올바른 방법인지는 확실치 않아서 좀 더 알아봐야 할 것 같다.
'Android > Architecture' 카테고리의 다른 글
Android - State Pattern (0) | 2021.11.13 |
---|---|
Android - TDD 셋업하기 (Unit Test) (0) | 2021.10.13 |
안드로이드 MVVM 패턴 익히기 (3) Repository + DI (0) | 2021.01.02 |
안드로이드 MVVM 패턴 익히기 (2.5) Coroutine (0) | 2020.12.29 |
안드로이드 MVVM 패턴 익히기 (2) LiveData+ViewModel (0) | 2020.12.27 |