Android Architecture Components
업데이트:
카테고리: Android
/태그: App architecture, UI Controller, ViewModel, ViewModelFactory
무엇을 배우는가?
- 권장되는 App Architecture 사용법
- 앱에서 LifeCycle, ViewModel, ViewModelFactory 사용
- 구성 변경시 UI 데이터를 유지
- factory 메서드 디자인 패턴 사용법
- ViewModelProvider.Factory를 사용하여 ViewModel 객체 생성
GuessTheWorld 앱의 문제
- 앱을 껐다 다시 켰을 때 데이터가 저장되지 않은 문제
- End Game 클릭시 작동하지 않는 문제
App architecture
앱은 크기가 커지기 때문에 앱을 확장하고 견고성을 높이며 앱을 쉽게 테스트 할 수 있도록 앱을 정의하는 것이 중요하다.
안드로이드 앱 아키텍쳐는 MVVM 모델과 비슷하다.
설계 원칙
-
관심사 분리 UI 기반의 클래스는 UI 및 운영체제 상호작용을 처리하는 로직만 포함해야 한다.
이렇게 클래스를 최대한 가볍게 유지하여 구성요소의 수명 주기와 관련된 문제를 피하고, 테스트 가능성을 개선할 수 있다. -
데이터 모델에서 UI 도출하기 데이터 모델은 앱의 데이터를 나타내며, 앱의 UI 요소 및 구성요소로 부터 독립되어 있다.
즉, 데이터 모델은 UI와 앱 구성요소 수명주기와는 관련이 없다.
하지만 OS가 메모리에서 앱의 프로세스를 삭제하기로 결정하면 데이터 모델도 삭제된다.지속적인 모델이 이상적인 이유
- OS에서 리소스를 확보하기 위해 앱을 제거해도 사용자 데이터가 삭제되지 않는다.
- 네트워크 연결이 취약하거나 연결되어 있지 않아도 앱이 계속 작동한다.
-
단일 소스 저장소 새로운 데이터 유형을 정의할 때는 데이터 유형에 단일 소스 저장소(SSOT)를 할당해야 한다. SSOT는 데이터의 소유자이며, SSOT만 데이터를 수정하거나 변경할 수 있다.
이를 위해 불변 유형을 사용하여 데이터를 노출하며, 다른 유형이 호출할 수 있는 이벤트를 수신하거나 함수를 노출하여 데이터를 수정한다.SSOT의 장점
- 특정 유형 데이터의 모든 변경사항을 한곳으로 일원화한다.
- 다른 유형이 조작할 수 없도록 데이터를 보호한다.
- 데이터의 변경사항을 쉽게 추척할 수 있도록하여 버그 발견이 쉬워진다.
-
단방향 데이터 흐름 단방향 데이터 흐름(UDF)에서 상태는 한 방향으로만 흐르고 데이터의 흐름을 수정하는 이벤트는 반대방향으로 흐른다.
안드로이드에서는 상태, 데이터는 일반적으로 상위 유형에서 하위 유형으로 흐른다.
이벤트는 하위 유형에서 트리거되어 상응하는 데이터 유형의 SSOT에 도달한다.
예로 애플리케이션 데이터는 데이터 소스에서 UI로 흐른다.
사용자 이벤트(버튼 누르기)는 UI에서 SSOT로 흐르며, SSOT에서는 데이터가 불변 유형으로 수정 및 변경된다.
이 패턴으로 데이터 일관성을 강화하고 오휴발생 확률을 감소시키고, 쉬운 디버그, SSOT 패턴의 장점을 사용할 수 있다.
현재 사용하는 앱에서는 UI controlloer
, ViewModel
, ViewModelFactory
로 구성되어 있다.
UI controller
Activity, Fragment 와 같은 UI기반의 클래스이다.
이 클래스는 UI 조작이나 상호작용과 같은 로직을 가지고 있다.
여기에는 의사 결정 로직을 만들면 안된다.
ViewModel
Activity, Fragment에 표시된 데이터를 가지고 있다.
UI 컨트롤에 표시될 데이터에 대한 간단한 계산이나 변환을 할 수 있다.
여기에서는 의사 결정을 할 수 있다.
ViewModelFactory
생성자 매개변수를 사용하거나 사용하지 않고 ViewModel 객체를 인스턴스화 한다.
ViewModel 만들기
- 종속성 추가하기
최근 버전으로 설치하고 실행되지 않는다면
2.2.0
으로 다운그레이드 하여 실행해본다.implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
- 클래스 만들기
lifecycle에 있는 ViewModel() 클래스를 가져온다.
class exampleCalss : ViewModel() { init { Log.i("exampleClass", "created") } }
- ViewModel 설치
구성 변경이 일어날 때 UI Controller는 다시 재생성되지만 ViewModel의 인스턴스는 살아있다.
ViewModel
클래스를 사용하여ViewModel
인스턴스를 만든다면, 새로운 객체는 fragment가 재 생성될 때마다 만들어 지게된다.
대신에 ViewModelProvider
을 사용하여 ViewModel
인스턴스를 만들게 된다면?
ViewModelProvider가 하는일
- 존재하는
ViewModel
을 반환하거나 존재하지 않을 때는 새롭게 만든다. - 주어진 Activity나 Fragment와 함께
ViewModel
인스턴스 생성한다. - 생성된
ViewModel
인스턴스는 Activity나 Fragment가 살아있는 한 남아있다.
ViewModelProvider.get()
을 활용하여 ViewModel
을 만들어보자
viewModel = ViewModelProvider(this).get(GameViewModel::class.java)
ViewModel
을 추가하기 전- 구성 변경을 거치면 GameFragment가 소멸되고 재생성된다. 하지만 데이터는 손실된다.
ViewModel
를 추가하고 Framgment의 데이터를ViewModel
로 이동할 때- 보여주기 위한 Fragment 데이터는
ViewModel
에 존재한다. - 구성변경이 일어날 때, ViewMdoel은 소멸하지 않고 데이터는 남아있게 된다.
- 보여주기 위한 Fragment 데이터는
No Static method metafactory
app 레벨의 build.gradle
에 아래의 코드를 추가한다.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
ViewModel에서 진행중인 데이터 옮기기
GameFragment
-> GameViewModel
private
이면 안된다. 데이터를 다른 클래스로 옮길것이기 때문에
view 참조가 포함되어 있기 때문에, binding 변수로 옮기지 말자.
해당 에러가 왜 발생하는지 모르겠음