ViewModel은 안드로이드 Lifecycle aware 객체로, Lifecycle을 고려하여 UI 데이터를 저장하고 관리하도록 설계되었습니다. 그렇기 때문에 ViewModel 객체는 ViewModelProvider를 통해서 생성하며, 직접 생성자를 호출하여 생성하지는 않습니다.
ViewModel의 생성자의 인자가 있냐 없냐에 따라서 생성 방법이 달라집니다.
- ViewModel의 생성자에 인자가 없는 경우 : ViewModelProvider로 VidwModel 객체를 생성할 수 있음.
- ViewModel의 생성자에 인자가 있는 경우 : ViewModelProvider.Factory 클래스를 구현하면 ViewModelProvider 생성자에 인자를 전달하여 객체를 생성할 수 있음.
인자가 없다면 ViewModelProvider만으로 간단히 객체를 생성할 수 있지만, 인자가 있는 경우는 Factory 클래스를 추가로 구현하여 어떤 인자를 생성자에 전달할지 ViewModelProvider에게 알려줘야 합니다.
예제를 통해서 자세히 알아보겠습니다. 전체 코드는 GitHub - ViewModelFactorySample에 올려두었으니 필요하시면 참고하세요.
1. 인자 없는 ViewModel 객체 생성
아래 클래스는 인자가 없는 ViewModel 클래스입니다.
class MainActivityViewModel : ViewModel() {
val result = MutableLiveData<String>("init value")
}
Activity에서 ViewModelProvider를 통해 다음과 같이 ViewModel 객체를 생성할 수 있습니다.
val viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
ViewModelProvider(this)
에서 this는 ViewModelStoreOwner를 의미합니다. Activity가 ViewModelStoreOwner 인터페이스를 구현하고 있기 때문에, Activity에서 this를 사용하시면 됩니다.
2. 인자가 있는 ViewModel 객체 생성
다음 클래스는 MyRepository 객체를 인자로 받는 ViewModel 클래스입니다.
class FirstActivityViewModel(
private val repository: MyRepository
) : ViewModel() {
val result = MutableLiveData<String>("init value")
fun reloadResults() {
result.value = repository.getResult()
}
}
Factory class 구현
ViewModelProvider는 ViewModel을 생성할 때 어떤 객체를 인자로 전달해줘야할지 모르니까, 아래와 같은 Factory 클래스를 정의해서 어떤 인자를 생성자에 전달할 지 정의해줘야 합니다.
class ViewModelFactory(private val repository: MyRepository)
: ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(FirstActivityViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return FirstActivityViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
ViewModel 생성
ViewModel을 생성할 때는, 아래와 같이 먼저 Factory 객체를 생성합니다. 그리고 ViewModelProvider에 Factory를 전달하여 ViewModel을 생성합니다.
ViewModelProvider는 내부적으로 위에서 구현한 Factory의 create()
메소드를 호출하여 인자가 있는 ViewModel을 생성합니다.
val repository = MyRepository()
val viewModelFactory = ViewModelFactory(repository)
val viewModel = ViewModelProvider(this, viewModelFactory).get(FirstActivityViewModel::class.java)
3. 인자가 없는 AndroidViewModel 객체 생성
AndroidViewModel는 ViewModel인데, App의 Context 정보를 알고 있는 ViewModel입니다. AndroidViewModel 객체도 ViewModelProvider를 통해서 생성해야 합니다.
다음은 간단한 형태의 AndroidViewModel 클래스입니다.
class SecondActivityViewModel(application: Application)
: AndroidViewModel(application) {
}
다음과 같이 ViewModelProvider으로 ViewModel 객체를 생성할 수 있습니다. ViewModelProvider의 인자로 AndroidViewModelFactory 객체를 함께 전달합니다.
val viewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application))
.get(SecondActivityViewModel::class.java)
4. 인자가 있는 AndroidViewModel 객체 생성
다음은 MyRepository 객체를 인자로 받는 AndroidViewModel 클래스입니다.
class ThirdActivityViewModel(
application: Application, private val repository: MyRepository
) : AndroidViewModel(application) {
}
Factory class 구현
위에서 구현한 Factory 클래스처럼, Application과 MyRepository 객체를 ApplicationViewModel의 생성자에 전달합니다.
class ViewModelFactory(private val application: Application, private val repository: MyRepository)
: ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ThirdActivityViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return ThirdActivityViewModel(application, repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
ViewModel 생성
ApplicationViewModel도 다음과 같이 Factory 객체를 ViewModelProvider에 전달하여 ViewModel 객체를 생성합니다.
val repository = MyRepository()
val viewModelFactory = ViewModelFactory(application, repository)
val viewModel = ViewModelProvider(this, viewModelFactory)
.get(ThirdActivityViewModel::class.java)
References
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력