✍ 코드를 작성할 때 Activity
혹은 Fragment
와 같은 UI 기반의 클래스는 📌 UI 및 OS 상호작용을 처리하는 로직만 포함해야 합니다. 이는 UI 클래스를 최대한 가볍게 유지하여 Lifecycle 관련 문제를 피하기 위함입니다.
UI 클래스는 무언가를 소유하는 것이 아닌 OS와 앱 사이의 계약을 나타내도록 이어주는 클래스일 뿐이며, 따라서 OS는 메모리 부족과 같은 특정 상황이 발생하면 언제든지 UI 클래스를 제거할 수 있습니다.
요약하자면, UI 클래스로부터 UI, OS 상호작용을 제외한 다른 로직을 분리하여 📌 UI 클래스에 대한 의존성을 최소화하는 것이 앱 관리 측면에서 좋습니다. 👍
UI는 Model에서 만들어져야 합니다. Model은 앱의 데이터 처리를 담당하는 컴포넌트로, 📌 앱의 View
객체 및 앱 컴포넌트와 독립되어 있으므로 앱의 Lifecycle에 영향을 받지 않습니다.
Model은 가급적 지속적인 Model을 사용하는 것이 👍 좋은데, 이는 지속 Model을 사용하면 OS에서 리소스 확보를 위해 앱을 제거해도 사용자 데이터가 삭제되지 않고 네트워크에 문제가 있어도 앱이 계속 작동📳하게 할 수 있기 때문입니다.
AAC(Android Architecture Components)는 테스트와 유지보수가 쉬운 앱을 디자인할 수 있도록 돕는 라이브러리의 모음입니다.
ViewModel은 앱의 Lifecycle을 고려하여 📌 UI 관련 데이터를 저장하고 관리하는 컴포넌트입니다.
UI Controller로부터 UI 관련 데이터 저장 및 관리를 분리하여 ViewModel이 담당하도록 하면 다음과 같은 문제를 해결🔧할 수 있습니다.
안드로이드 프레임워크는 특정 작업이나 완전히 통제할 수 없는 기기 이벤트에 대한 응답으로 UI Controller를 제거하거나 다시 만들 수 있는데, 이런 경우 UI Controller에 저장된 모든 일시적인 UI 관련 데이터가 삭제됩니다. 단순한 데이터의 경우 onSaveInstanceState()
메서드를 사용하여 복구할 수 있지만 대용량의 데이터의 경우엔 불가능합니다.
UI Controller에서 데이터를 위한 비동기 호출을 한다면 메모리 누수 가능성을 방지하기 위한 많은 유지 관리가 필요하며, 위에서와 같이 데이터를 복귀해야 하는 경우 비동기 호출을 다시해야 해서 리소스가 낭비됩니다.
UI Controller에서 DB나 네트워크로부터 데이터를 로드하도록 하면 다른 클래스로 작업이 위임되지 않고 단일 클래스가 혼자서 앱의 모든 작업을 처리하려고 할 수 있습니다. 이 경우 테스트가 훨씬 더 어려워집니다.
ViewModel은 ViewModel
클래스를 상속받아 구현합니다.
class MyViewModel : ViewModel() {
/* by lazy: val 데이터의 늦은 초기화 방법 */
private val users: MutableLiveData<List<User>> by lazy {
/* .also: scope function */
MutableLiveDate().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
UI 클래스에서는 다음과 같은 방법으로 ViewModel
에 접근할 수 있습니다.
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
/* by viewModels(): model의 getValue/setValue 동작을
viewModels의 getValue/setValue의 동작에 위임 */
val model: MyViewModel by viewModels()
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI
})
}
}
ViewModel
객체는 뷰 또는 LifecycleOwners
보다 오래 지속되도록 설계되었으며, ViewModel
을 가져올 때 ViewModelProvider
에 전달되는 LifecycleOwners
에 따라 Lifecycle이 달라집니다. 만약 액티비티가 전달되었다면 액티비티가 종료될 때까지, 프래그먼트가 전달되었다면 프래그먼트가 분리될 때까지 ViewModel
은 메모리에 남아 있습니다.
LiveData는 📌 식별 가능한 데이터 홀더 클래스로 다른 앱 컴포넌트의 Lifecycle을 인식하며, 이를 통해 📌 활성 상태에 있는 앱 컴포넌트 옵저버에게만 업데이트 정보를 알립니다.
LiveData를 사용하면 다음과 같은 이점이 있습니다.
Observer Pattern
을 따르며 Lifecycle 상태가 변경될 때마다 Observer
객체에 알립니다. 또 앱 데이터의 변경이 발생할 때마다 관찰자에게 알려 UI를 업데이트할 수 있도록 합니다. Observer
는 Lifecycle 객체에 결합되어 있으며 연결된 객체의 Lifecycle이 끝나면 자동으로 삭제됩니다. Observer
가 비활성 상태에 있으면 어떤 LiveData 이벤트도 받지 않습니다.LiveData 객체는 다음과 같은 순서로 사용됩니다.
ViewModel
클래스 내에서 특정 유형의 데이터를 보유할 LiveData
의 인스턴스를 만듭니다.onChanged()
메서드를 정의하는 Observer
객체를 UI Controller에 만듭니다. onChanged()
메서드는 LiveData
객체가 보유한 데이터가 변경될 경우 발생하는 작업을 제어합니다.observe()
메서드를 사용하여 LiveData
객체에 Observer
객체를 연결합니다. LiveData
객체를 업데이트하는 경우 MutableLiveData
클래스는 setValue(T)
또는 postValue(T)
메서드로 LiveData
객체에 저장된 값을 수정합니다.Room 라이브러리는 SQLite에 추상화 레이어를 제공하여 원활한 DB 액세스를 지원하고 SQLite를 완벽히 활용할 수 있게 하는 라이브러리입니다.
Room 라이브러리를 사용하면 앱을 실행하는 기기에서 앱 데이터의 캐시를 만들 수 있으며, 이 캐시를 통해 사용자는 인터넷 연결 여부와 관계없이 앱에 있는 주요 정보를 일관된 형태로 볼 수 있습니다.