일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 컴포즈
- MVVM
- DiffUtil
- XML
- 코틀린
- Jetpack
- 회원가입
- 뷰
- Kotlin
- sharedFlow
- 커스텀뷰
- 로그인
- 알고리즘
- coroutine
- 클린아키텍처
- Build variants
- Authentication
- UiState
- Android
- Flow
- NavController
- 파이어베이스
- 안드로이드
- 리사이클러뷰
- cleanarchitecture
- Compose
- 코딩테스트
- ListAdapter
- 플레이스토어
- NavHost
- Today
- Total
Grusie 안드로이드 개발 기술 블로그
[Android] 뷰모델에 런타임 오브젝트 의존성 주입하기(@AssistedInject) 본문
기존 HiltViewModel을 사용했을 때에는 생성자에 의존성이 선언 되어있는 useCase들을 넘겨주는 형태로 사용하였으나, 생성자를 넣어주고 싶어 찾아보다 Assisted Inject에 대해 발견하게 되어 기록해보려고 한다.
사용법
1. @HiltViewModel을 사용하지 않는다.
2. 뷰모델의 constructor 앞에 @Inject를 @AssistedInject로 대체한다.
3. 생성자에 들어갈 파라미터 중 런타임 오브젝트를 주입받는 파라미터에는 @Assisted 애너테이션을 넣는다.
4. 생성자를 주입한 뷰모델을 리턴하는 뷰모델 팩토리를 선언한다.
5. 뷰에서 뷰모델 팩토리를 사용하여, 뷰모델을 생성한다.
직접 구현해보자
class SlowMailBoxViewModel @AssistedInject constructor(
private val getLocalUserInfoUseCase: GetLocalUserInfoUseCase,
private val setLocalUserInfoUseCase: SetLocalUserInfoUseCase,
private val slowMailBoxUseCases: SlowBoxUseCases,
@Assisted private val spaceId: Long,
@Assisted private val slowMailType: Int?
) : ViewModel() {
...
}
해당 뷰모델에 @AssistedInject constructor로 필요한 파라미터를 입력해주고, 동적으로 런타임에 주입받을 파라미터에@Assisted를 입력해준다.
Hilt ViewModel을 사용하는 것이 아니라, @HiltViewModel을 사용하지 않는다.
참고)
HiltViewModel을 사용하면서, 동적으로 런타임에 주입받을 파라미터가 존재한다면, SavedStateHandle을 사용하여 뷰모델 팩토리에서 생성해주면 될 것 같다.
뷰모델 팩토리 선언
@AssistedFactory
interface SlowMailBoxViewModelFactory {
fun create(spaceId: Long, slowMailType: Int?): SlowMailBoxViewModel
}
뷰모델 팩토리를 인터페이스로 선언을 해준 뒤, create를 통해 뷰모델을 생성할 예정이다.
런타임에 주입받을 파라미터는 spaceId, slowMailType 이렇게 두 개이다.
spaceId와 slowMailType은, SlowMailBoxViewModel을 사용하기 위해 꼭 필요한 파라미터로서, 다음 페이지로 이동할 때에도 사용될 것이며 한 번 지정되면 변경이 되지 않고, 이 값들에 따라서 서버통신을 진행하기에 생성자 파라미터로 넘겨주는 것을 택했다.
create()함수 구현
companion object {
fun provideFactory(
slowMailBoxViewModelFactory: SlowMailBoxViewModelFactory,
spaceId: Long,
slowMailType: Int?
): ViewModelProvider.Factory = object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return slowMailBoxViewModelFactory.create(spaceId, slowMailType) as T
}
}
}
뷰모델 팩토리에서, viewModel을 생성해주는 create함수를 오버라이딩 해, 우리가 구현했던, SlowMailBoxViewModelFactory를 통해서 뷰모델을 생성하도록 구현하였다.
뷰모델을 사용할 액티비티
private var spaceId: Long = 0
private var slowMailType: Int = 0
@Inject
lateinit var slowMailBoxViewModelFactory: SlowMailBoxViewModel.SlowMailBoxViewModelFactory
private val viewModel by viewModels<SlowMailBoxViewModel> {
SlowMailBoxViewModel.provideFactory(slowMailBoxViewModelFactory, spaceId, slowMailType)
}
뷰모델 팩토리를 @Inject 애너테이션을 추가하여, lateinit으로 생성 후, 각 파라미터들을 사용해서 ViewModel을 생성하도록 구현
spaceId = intent.getLongExtra(SlowMailBoxActivity.EXTRA_SPACE_ID, 0)
slowMailType = intent.getIntExtra(EXTRA_TYPE, TYPE_RECEIVED)
이전 화면에서 뷰모델에 들어갈 파라미터들을 Intent로 받아와 넣어주며, 추 후 뷰모델이 사용될 어딘가에서, 뷰모델이 생성될 것이다.
런타임에서 생성자에 파라미터를 넣었을 때의 장점
1. 뷰모델에서 초기 데이터를 init 함수에서 가져올 수 있다.
init {
if(slowMailType == null) fetchData() else fetchDataWithType()
}
2. 생성자를 setter로 지정했을 경우, 코드 실수를 했을 때 컴파일 에러로 판단할 수 없다.
3. 테스트 코드 작성 시 필요한 데이터 주입을 간단히 할 수 있다.
참고
후기
생성자에 필요한 정보들을 setter를 사용해서 넣었었는데, 그랬기에 init함수에서 데이터를 가져오지 못하고, setter 호출 후, fetchData()를 직접 호출해주었어야 했다.
이렇게 변경하고 나니, 뷰에서 신경쓸 코드가 더 줄어들어서 유지보수성을 증가시킬 수 있었던 것 같다.
'안드로이드 개발' 카테고리의 다른 글
[Android] Debug / Release 분리해서 작업하기 (0) | 2024.07.10 |
---|---|
[Android] Build Variants로 개발단계에서 release 버전 테스트 하기 (0) | 2024.07.04 |
[Android] 이미지 저장 및 삭제 로직 공유 (1) | 2024.06.14 |
[Android] 커스텀 갤러리 만들기(이미지 불러오기, 다중 이미지 선택) (0) | 2024.05.27 |
[Android] release 버전에서 Gson 파싱이 안 되던 오류(코드 난독화 문제) (0) | 2024.05.07 |