티스토리 뷰

ViewModel 자동 DI
1. 키생성
@MapKey
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class ViewModelKey(
val value: KClass<out ViewModel>,
)
다음과 같이 ViewModelKey 어노테이션 클래스를 생성한다. 이 어노테이션을 ViewModel에 달아주면 해당 ViewModel이 밑의 코드에 있는 viewModelProviders에 저장할 키 값임을 명시하는 것이다.
2. 커스텀 ViewModelFactory생성
@ContributesBinding(AppScope::class)
class MetroViewModelFactory @Inject constructor(
private val creators: Map<KClass<out ViewModel>, Provider<ViewModel>>,
) : ViewModelProvider.Factory {
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
override fun <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras,
): T {
val provider = creators[modelClass.kotlin] ?: error("$modelClass")
return modelClass.cast(provider())
}
}
위의 코드와 같이 MetroViewModelFactory 객체에서 viewModelProviders에 값을 넣어줄 수 있다.
creators는 Metro가 자동으로 생성하여 주입해주기 때문에 따로 그래프에 정의를 하거나 어노테이션을 통해 등록해주지 않아도 된다.
@ContributesIntoMap(AppScope::class)
@ViewModelKey(SettingViewModel::class)
class SettingViewModel @Inject constructor(
private val festivalNotificationRepository: FestivalNotificationRepository,
) : ViewModel() {
...
}
@ContributesIntoMap을 사용하여 해당 스코프 안에서, Map에 저장할 수 있도록 하며 위에서 언급했던 것 처럼 @ViewModelKey가 ViewModel을 찾는 키 역할을 하게 된다.
@ContributesIntoMap(
scope = AppScope::class,
binding = binding<Fragment>(),
)
@FragmentKey(SettingFragment::class)
@Inject
class SettingFragment(
private val notificationPermissionManagerFactory: NotificationPermissionManager.Factory,
) : BaseFragment<FragmentSettingBinding>(),
NotificationPermissionRequester {
override val layoutId: Int = R.layout.fragment_setting
override val defaultViewModelProviderFactory: ViewModelProvider.Factory
get() = appGraph.metroViewModelFactory
private val settingViewModel: SettingViewModel by viewModels({ requireActivity() })
defaultViewModelProviderFactory를 오버라이딩해서 커스텀한 MetroViewModelFactory와 연결해주면 by viewModel()을 통해 뷰모델 객체를 생성할 때 자동으로 MetroViewModelFactory를 통해 viewModel 객체를 생성해준다.
수동 ViewModel 생성
하지만 @Assisted, @AssistedFactory을 ViewModel의 생성자 파라미터로 사용할 경우는viewModelProviders에 넣어줄 수 없다.
class ScheduleViewModel @AssistedInject constructor(
private val scheduleRepository: ScheduleRepository,
@Assisted private val dateId: Long,
) : ViewModel() {
@AssistedFactory
interface Factory {
fun create(dateId: Long): ScheduleViewModel
}
...
}
따라서 다음과 같이 Factory 메서드를 직접 구현 해준 후, 수동으로 생성해주어야한다.
companion object {
const val INVALID_ID: Long = -1L
fun factory(
factory: Factory,
dateId: Long = INVALID_ID
): ViewModelProvider.Factory =
viewModelFactory {
initializer {
factory.create(dateId)
}
}
}
private val viewModel: ScheduleViewModel by viewModels {
val dateId: Long = arguments?.getLong(KEY_DATE_ID, INVALID_ID) ?: INVALID_ID
ScheduleViewModel.factory(appGraph.scheduleViewModelFactory, dateId)
}
모르는게 아직 많지만 일단 정리해보았다. 나중에 다시 열어보면 부끄러운 코드가 될 듯하다.
'안드로이드' 카테고리의 다른 글
| LifeCycle Of View (0) | 2025.12.09 |
|---|---|
| Hilt, Metro의 DI 그래프 생성, 등록, 주입 차이 (0) | 2025.12.08 |
| Lottie (0) | 2025.11.05 |
| LifeCycle Of ViewModel (1) | 2025.10.05 |
| Android Thread 통신과 Handler·Looper (4) | 2025.08.29 |