@Composable
fun HomeScreen(
..
viewModel: HomeViewModel = hiltViewModel()
)
Hilt와 Compose를 사용하면서 뷰모델을 생성할 때 hiltViewModel() 이라는 편한 기능이 있습니다.
@HiltViewModel
class HomeViewModel @Inject constructor(
private val placeReadUseCase: PlaceReadUseCase
): ViewModel() {
...
하지만 @HiltViewModel 어노테이션을 볼 때 짐작 가능하듯이, 해당 뷰모델의 파라미터에는 Hilt에 관련된 것만 삽입할 수 있습니다. 즉 Hilt는 동적으로 변하는 인자값을 자동으로 주입 할 수 없습니다!
class PlaceDetailViewModel @AssistedInject constructor(
@Assisted private val place: String,
private val getPlaceInfoUseCase: GetPlaceInfoUseCase,
): ViewModel()
먼저, @HiltViewModel 어노테이션을 제거한 후 동적인자를 받기위해 @Inject 대신 @AssistedInject 어노테이션으로 수정합니다.
동적으로 받는 인자 또한 @Assisted 어노테이션을 붙여야합니다!
@AssistedFactory
interface PlaceDetailViewModelFactory {
fun create(place: String): PlaceDetailViewModel
}
뷰모델 내부에 동적 인자를 받을 수 있는 팩토리 인터페이스를 정의합니다.
...
companion object{
fun providePlaceDetailViewModelFactory(
factory: PlaceDetailViewModelFactory,
place: String
): ViewModelProvider.Factory{
return object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return factory.create(place) as T
}
}
}
}
해당 부분도 뷰모델 내부에 뷰모델을 생성할 수 있는 팩토리를 제공하는 정적 함수를 정의합니다.
이 팩토리 내부에는 재정의된 함수 create()가 있고 해당 함수의 반환값에 동적으로 변할 인자값을 넣습니다.
@EntryPoint
@InstallIn(ActivityComponent::class)
interface ViewModelFactoryProvider {
fun placeDetailViewModelFactory(): PlaceDetailViewModel.PlaceDetailViewModelFactory
}
현재 주입받는 컨텍스트가 엑티비티, 프래그먼트가 아닌 Compose에서 진행되기 때문에 EntryPoint를 정의해줘야 합니다!
그리고 @InstallIn 어노테이션을 이용해 엑티비티 생명주기에 맞춰서 관리되도록 선언해줍니다!
마지막으로, 사용할 뷰모델의 팩토리를 주입할 수 있도록 함수를 정의합니다!
@Composable
fun PlaceDetailScreen(
navController: NavController,
place: String?,
){
val factory = EntryPointAccessors.fromActivity(
LocalContext.current as Activity,
ViewModelFactoryProvider::class.java
).placeDetailViewModelFactory()
val viewModel: PlaceDetailViewModel = viewModel(
factory = PlaceDetailViewModel.providePlaceDetailViewModelFactory(factory, place ?: "")
)
...
EntryPoint에 접근해 위에서 정의한 팩토리를 불러옵니다!
현재는 placeDetailViewModelFatory()가 필요하니 해당 팩토리를 참조해 주입받습니다!
이후 뷰모델을 선언하고, 뷰모델을 생성하기 위한 팩토리와, 동적인자를 넣어주면 끝입니다!!
테스트한 애플리케이션의 시나리오는 지역카드를 클릭하면 상세페이지로 이동합니다.
이동한 페이지는 지역에 대한 페이지이므로 지역명이 필요합니다. 상세페이지의 지역명은 정적이아닌, 동적인 개념이라 해당 내용을 적용했습니다!
간단한 파라미터 값만 넣는대도 설정 할 값들도 너무 많아서 당항스러웠습니다 😂
그리고 Hilt를 공부 할 수록 더 어려워지는구나...하고 생각했습니다.
https://www.simplifiedcoding.net/assisted-injection-in-viewmodel/