안녕하세요 :)
이전 포스팅에서 MVVM에 대해 알아봤습니다만,
2022.05.30 - [Android] - [Android] Pattern (MVC, MVP, MVVM)
막상 MVVM으로 구현하려니, 적용이 꽤나.. 어려웠습니다 🥶
그래서 MVVM을 구현 시 알아둬야할 부분에 대해 자세한 개념보다는 어떻게 써야하는지를 정리하려고 합니다
.. 멀고도 험한 MVVM의 길 😮💨
⚒ Skill ⚒
- ViewModel
- LiveData
- DataBinding
- Repository
- Dagger
ViewModel
- AAC (Clean Architecture을 쉽게 구현하도록 제공되는 library) 중 하나
- LifeCycle을 고려해 UI 관련 데이터를 저장하고 관리
👀 ViewModle을 사용하는 이유
화면 회전, 시스템 폰트 크기 변경 등 구성이 변경 시 액티비티가 재시작되며 데이터가 날아가기 때문에, 데이터 저장 및 복원 작업이 필요합니다.
물론 기존에 방법이 없었던 것은 아니에요. onSaveInstanceState()를 사용할 수도 있습니다
하지만, 기존 방법엔 문제점이 있어요
1) 저장할 수 있는 데이터의 양이 적다
2) fun onCreate(savedInstanceState: Bundle?)에서 데이터를 저장 및 복원하는 처리가 필요합니다
UI Controller는 최소한의 로직을 가져야 하는데, 이 경우엔 적합하지 않겠죠 ( 아키텍처 가이드(관심사 분리) 참조)
3) UI Controller에 데이터 저장 및 복원 ▶️ 메모리 부족과 같은 시스템 이슈로 언제든 제거가 가능해 적합하지 않습니다
위와 같은 문제점을 해결하기 위해 ViewModel이 등장했습니다
Repository
- ViewModel이 비즈니스 로직에 집중하기 위해 데이터의 초기화 및 데이터에 직접 접근을 하는 클래스
즉, API 호출 및 Response 전달을 Repository에서 한다고 생각하면 됩니다 (데이터 통신을 담당)
- 모듈화 명확, 유지보수 용이
LiveData
- AAC의 일부, LifeCycle을 인식하며 관찰 가능한 데이터 홀더 클래스
- LifecycleOwner(Activity 혹은 Fragment)와 연결해야 합니다
- LiveData 객체 내의 데이터에 액세스하려면 value 속성을 사용합니다
val currentData : MutableLiveData<String>
get() = _currentData
fun getNextWord() {
_currentData.value = String(텍스트)
}
fun setNextWord(str: String) {
_currentData.postValue(str)
}
📣 MVVM 구현하기
1. ViewModel 클래스 생성
다른 클래스에서 데이터를 수정하면 안되기 때문에 private으로 선언
만약, 외부에서 데이터를 읽을 수 있어야 한다면 public val로 선언
class MainViewModel(val repository: MainRepository): ViewModel() {
val _currentData: MutableLiveData<List<String>>
}
2. Repository 생성
API를 호출하고, ViewModel로 데이터를 전달합니다
(예제에선 Dagger를 통해 Rest API를 주입받습니다)
class MainRepository {
@Inject
lateinit var api: MainAPI
var _currentData: MutableLiveData<List<String>>
fun getList() {
//api에서 데이터를 가져오는 함수
_currentData = api에서 가져온 데이터
}
fun sendList() : MutableLiveData<List<String>> {
return _currentData
}
}
3. ViewModel 객체 생성
ViewModel 객체의 생성은 크게 2가지 방법으로 나뉩니다
ViewModelProviders를 사용은 Deprecated 되었으므로, ViewModelProvider를 사용하겠습니다
1) 인자가 없는 경우
- ViewModelProvider로 ViewModel 객체 생성
viewModel = ViewModelProvider(this).get(뷰모델클래스명::class.java)
- ViewModelProvider(ViewModelStoreOwner)
- Activity와 Fragment는 ViewModelStoreOwner를 포함하므로 this를 넣습니다
2) 인자가 있는 경우
- ViewModelProvider(ViewModelStoreOwner, ViewModelProvider.Factory)로 객체 생성
- 인자가 있을 경우는, ViewModelProvider에 해당 객체를 생성할 수 있는 방법을 제공해야 합니다.
- ViewModelProvider에 객체 생성 방법을 제공하기 위해 ViewModel 라이브러리에서 ViewModelProvider.Factory를 제공합니다
[ViewModelProvider.Factory 생성]
class MainViewModelFactory(val repository: MainRepository): ViewModelProvider.Factory {
override fun <T: ViewModel?> create(modelClass: Class<T>: T {
return modelClass.getConstructor(MainRepository::class.java).newInstance(repository)
}
}
- 생성된 팩토리를 ViewModelProvider의 인자로 설정해줍니다
val factory = MainViewModelFactory(repository)
val viewModel = ViewModelProviders.of(this, factory).get(뷰모델클래스명::class.java)
4. ViewModel에서 Repository 가져오기
class MainViewModel(val repository: MainRepository): ViewModel() {
val _currentData: MutableLiveData<List<String>>
fun getCurrentData() : MutableLiveData<List<String>> {
return repository().getCurrent()
}
}
선언된 LiveData와 Repository에서 가져오는 값을 연결하려면 Repository에서 반환하는 함수를 연결해주면 됩니다 !
fun getCurrentData() : MutableLiveData<List<String>> {
return repository().getCurrent()
}
그렇다면, ViewModel에서 선언된 Reponse를 반환하는 함수는 어떻게 활용할까요?
바로 UI Controller에서 사용하면 됩니다 !
5. View에서 ViewModel 사용하기
ViewModel에서 데이터를 반환하는
viewModel.getCurrentData.observe(lifeCycleOwner, { data->
binding.tvTxt.text = data[0]
})
observe에 의해, update와 관련된 메서드 없이 LiveData Observe에서 자동으로 업데이트 됩니다 👍🏻
궁금하신 점이나 의견이 있으시면 댓글 부탁드립니다 감사합니다 😊
'📱 Android' 카테고리의 다른 글
[Android] 4대 Component (0) | 2022.07.05 |
---|---|
[Android] Activity LifeCycle 🧐 (0) | 2022.07.03 |
[Android] Jetpack Architecture #1 DataBinding (0) | 2022.06.05 |
[Android] Pattern (MVC, MVP, MVVM) (0) | 2022.05.30 |
[Android] Clean Architecture in Android (0) | 2022.05.29 |