Android Hilt 사용하기
Hilt 사용하기
Spring 에서 서비스단의 클래스를 그냥 어노테이션으로 선언만하고 막쓰던것 처럼 DI해주는 Dagger 라는 라이브러리를 기반으로 안드로이드에서 HILT로 새로 내놓았다고함. Dagger 는 Android용이 아니었기 때문에 안드로이드에 맞는 Hilt라는 것을 내놓은거다.
Dagger + Android LifeCycle = HILT 라고 생각해도됨.
구글이 Hilt currently supports the following Android classes:
Application
(by using@HiltAndroidApp
)ViewModel
(by using@HiltViewModel
)Activity
Fragment
View
Service
BroadcastReceiver
만 지원한다네… 뭐 다되는거 아님?
@Inject 어노테이션으로 주입과 사용 양쪽에 사용한다. 사용자가 만든 클래스의 경우에는 Hilt가 삽입하고자 하는 곳에 초기화해서 사용하기 위해서 constructor 에 선언해주면 된다. 다만 안드로이드의 경우 프레임워크이고 라이프사이클이 있어서 Module 과 IntallIn 이라는 어노테이션으로 프레임워크의 어떤 부분에 해당 모듈을 사용할건지를 선언해줘야 한다.
@Module이 클래스에 지정하는 어노테이션이라고 하면, 개개별 메소드에는 @Provide 또는 @Bind를 통해 다른곳에서 Injection하여 끌어다가 사용할수 있도록 한다.
@Provide : 실제 코드를 구현하여 메소드에서 뭔가 작업할때 Object계열읠 클래스일때는 이걸쓴다.
@Bind : Abstract 클래스에서는 메소드도 추상화 시키기 때문에, 실제 구현 코드는
- 종속성추가
https://developer.android.com/training/dependency-injection/hilt-android?hl=ko
- Application 클래스를 생성하고 HiltAndroidApp이라고 사용함을 지정, MainActivity에 EntryPoint지정
https://github.com/sugoigroup/android_hilt_example/commit/66e062ae622674d70ed511ab526b95637399aa1b
- 간단하게 사용해보자
https://github.com/sugoigroup/android_hilt_example/commit/84c20d9e6c87108ae378852eb900ca63785278bd
-------------------------------
//사용하고자 하는 클래스 변수에 Inject 를 지정
@Inject
lateinit var calcme: CalcMe
...
// Inject 지정에 의해 calcme변수에 CalceMe객체가 할동되어있다.
Log.e("Test", calcme.sumMe(1, 2).toString())
-------------------------------
//사용하고자 하는 클래스 변수에 Inject 를 지정
class CalcMe @Inject constructor() {
fun sumMe(num1:Int, num2:Int) : Int {
return num1 + num2
}
}
- Module 간단한 사용.
https://github.com/sugoigroup/android_hilt_example/commit/112a15def5b62d2203bcfab40462ad3c82559185
--------------------------------
MyHiltModule.kt
@Module // Module은 클래스에 정의
@InstallIn(ApplicationComponent::class) //Application 의 라이프사이클에 맞추어 동작한다는 의미
class MyHiltModule {
@Singleton
@Provides
// 리턴 타입이 MainApplication 이라면 이게 실행됨.
fun provideMeApplication(@ApplicationContext app: Context): MainApplication {
// send data to server then receive results
return app as MainApplication
}
@Singleton
@Provides
// 리턴 타입이 Int형이라면 이게 실행
fun sendAndBringApiService(): Int {
// send data to server then receive results
return 200
}
@Singleton
@Provides
// 리턴 타입이 String 이라면 이게 실행
fun saveToRepository(): String = "Saved"
}
--------------------------------
MainActivity.kt
//변수에 Inject
@Inject
lateinit var myapp: MainApplication // MainApplication 을 리턴타입으로 하는 프로바이더 자동 삽입
var resultCode: Int = 0
@Inject set // Int 을 리턴타입으로 하는 프로바이더 자동 삽입
@Inject
lateinit var saveRepo: String // Int 을 리턴타입으로 하는 프로바이더 자동 삽입
//출력
Log.v("Test", "my app: ${myapp}")
Log.v("Test", "result Code: ${resultCode}")
Log.v("Test", "saveRepo result: ${saveRepo}")
- 같은 리턴타입의 프로바이더를 Qualifier 로 구분지어 호출하자.
https://github.com/sugoigroup/android_hilt_example/commit/f0df622bdddda5f8bb31db15509569c58774f7f8
--------------------------------
MyHiltModule.kt
@Module // Module은 클래스에 정의
@InstallIn(ApplicationComponent::class) //Application 의 라이프사이클에 맞추어 동작한다는 의미
class MyHiltModule {
@Singleton
@Provides
// 리턴 타입이 MainApplication 이라면 이게 실행됨.
fun provideMeApplication(@ApplicationContext app: Context): MainApplication {
// send data to server then receive results
return app as MainApplication
}
@Singleton
@Provides
// 리턴 타입이 Int형이라면 이게 실행
fun sendAndBringApiService(): Int {
// send data to server then receive results
return 200
}
@Singleton
@Provides
@SaveRepoAction
// 리턴 타입이 String 이고 @SaveRepoAction 이라면 이게 실행
fun saveToRepository(): String = "delete"
@Singleton
@Provides
@DeleteRepoAction
// 리턴 타입이 String 이고 @DeleteARepoction 이라면 이게 실행
fun deleteToRepository(): String = "Saved"
}
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
internal annotation class SaveRepoAction
@Qualifier
@Retention(AnnotationRetention.RUNTIME)
internal annotation class DeleteRepoAction
}
--------------------------------
MainActivity.kt
//변수에 Inject
@Inject @SaveRepoAction
lateinit var saveRepo: String // Int 을 리턴타입으로 하는 프로바이더 자동 삽입
@Inject @DeleteRepoAction
lateinit var deleteRepo: String // Int 을 리턴타입으로 하는 프로바이더 자동 삽입
//출력
Log.v("Test", "deleteRepo result: ${deleteRepo}")
Log.v("Test", "saveRepo result: ${saveRepo}")
- @bind로 사용자가 정의한 constructor를 써보자.
https://github.com/sugoigroup/android_hilt_example/commit/dfcd4f7e3b96efb2fa3274b98611665d2dd6e9c5
--------------------------------
MyHitAbs.kt
@Module
@InstallIn(ApplicationComponent::class)
abstract class MyHiltAbs{ //추상클래스를 모듈로 선언
@Singleton
@Binds //PowerInterfaceImpl 을 powerImpl에 Inject하고, PowerInterface형식을 선언하는 곳에 구현제를 바인드 해준다.
abstract fun bindMyComputer(powerImpl: PowerInterfaceImpl): PowerInterface
}
interface PowerInterface {
fun getPower(): String
}
class PowerInterfaceImpl @Inject constructor(): PowerInterface {
override fun getPower(): String {
return "Low Power(<220)"
}
}
// Binds에 의해 자동으로 powerImpl 변수는 PowerInterfaceImpl 구현체에 바인드 되어 진다.
class MyComputer @Inject constructor(private val powerImpl: PowerInterface) {
fun powerStart(): String {
return "${powerImpl.getPower()}" //구현체의 getPower가 실행된다.
}
}
--------------------------------
MainActivity.kt
@Inject
lateinit var myComputerBinded: MyComputer; //Inject와 동시에 Bind에 지정된 구현체가 연결된다.
Log.v("Test", "bind example: ${myComputerBinded.powerStart()}")
이밖에 ViewModel과의 연동도 가능한다.
저렇게 써놓으면 Hilt가 언제 내 소스에 관련 Injection 소스들을 쑤셔넣어주냐 하면,
- 구성요소 전체 기간
Hilt는 해당 Android 클래스의 수명 주기에 따라 생성된 구성요소 클래스의 인스턴스를 자동으로 만들고 제거합니다.
https://developer.android.com/training/dependency-injection/hilt-android#component-scopes
구글 공식사이트에서 이렇다고 한다.
참고
제일 자세한 한글 :https://hyperconnect.github.io/2020/07/28/android-dagger-hilt.html
dagger2가 궁금하다면 여기 : http://pluu.github.io/blog/android/2017/01/12/android-dagger/
0 comments:
댓글 쓰기