[Android] 안드로이드 AAC

Hwichan Ji·2021년 1월 19일
4

Android

목록 보기
1/7
post-thumbnail

앱 아키텍처 원칙

관심사 분리 🥇

✍ 코드를 작성할 때 Activity 혹은 Fragment와 같은 UI 기반의 클래스는 📌 UI 및 OS 상호작용을 처리하는 로직만 포함해야 합니다. 이는 UI 클래스를 최대한 가볍게 유지하여 Lifecycle 관련 문제를 피하기 위함입니다.

UI 클래스는 무언가를 소유하는 것이 아닌 OS와 앱 사이의 계약을 나타내도록 이어주는 클래스일 뿐이며, 따라서 OS는 메모리 부족과 같은 특정 상황이 발생하면 언제든지 UI 클래스를 제거할 수 있습니다.

요약하자면, UI 클래스로부터 UI, OS 상호작용을 제외한 다른 로직을 분리하여 📌 UI 클래스에 대한 의존성을 최소화하는 것이 앱 관리 측면에서 좋습니다. 👍

모델에서 UI 만들기 🥈

UI는 Model에서 만들어져야 합니다. Model은 앱의 데이터 처리를 담당하는 컴포넌트로, 📌 앱의 View 객체 및 앱 컴포넌트와 독립되어 있으므로 앱의 Lifecycle에 영향을 받지 않습니다.

Model은 가급적 지속적인 Model을 사용하는 것이 👍 좋은데, 이는 지속 Model을 사용하면 OS에서 리소스 확보를 위해 앱을 제거해도 사용자 데이터가 삭제되지 않고 네트워크에 문제가 있어도 앱이 계속 작동📳하게 할 수 있기 때문입니다.

AAC란?

AAC(Android Architecture Components)는 테스트와 유지보수가 쉬운 앱을 디자인할 수 있도록 돕는 라이브러리의 모음입니다.

ViewModel 🥇

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 🥈

LiveData는 📌 식별 가능한 데이터 홀더 클래스로 다른 앱 컴포넌트의 Lifecycle을 인식하며, 이를 통해 📌 활성 상태에 있는 앱 컴포넌트 옵저버에게만 업데이트 정보를 알립니다.

LiveData를 사용하면 다음과 같은 이점이 있습니다.

  • UI와 데이터 상태의 일치 보장: LiveData는 Observer Pattern을 따르며 Lifecycle 상태가 변경될 때마다 Observer 객체에 알립니다. 또 앱 데이터의 변경이 발생할 때마다 관찰자에게 알려 UI를 업데이트할 수 있도록 합니다.
  • 메모리 누수 없음: Observer는 Lifecycle 객체에 결합되어 있으며 연결된 객체의 Lifecycle이 끝나면 자동으로 삭제됩니다.
  • 중지된 활동으로 인한 비정상 종료 없음: 활동이 백 스택에 있을 때를 비롯하여 Observer가 비활성 상태에 있으면 어떤 LiveData 이벤트도 받지 않습니다.
  • Lifecycle을 더 이상 수동으로 처리하지 않음: UI 컴포넌트는 관련 데이터를 관찰하기만 할 뿐 관찰을 중지하거나 다시 시작하지 않으며, LiveData가 이를 자동으로 관리합니다.
  • 최신 데이터 유지: 컴포넌트가 비활성화되면 다시 활성화될 때 최신 데이터를 수신합니다.
  • 적절한 구성 변경: 기기 회전과 같은 구성 변경으로 인해 액티비티나 프래그먼트가 다시 생성되면 최신 데이터를 즉시 받게 됩니다.
  • 리소스 공유: 앱에서 시스템 서비스를 공유할 수 있도록 싱글톤 패턴을 사용하는 LiveData 객체를 확장하여 시스템 서비스를 래핑할 수 있습니다.

LiveData 객체는 다음과 같은 순서로 사용됩니다.

  1. ViewModel 클래스 내에서 특정 유형의 데이터를 보유할 LiveData의 인스턴스를 만듭니다.
  2. onChanged() 메서드를 정의하는 Observer 객체를 UI Controller에 만듭니다. onChanged() 메서드는 LiveData 객체가 보유한 데이터가 변경될 경우 발생하는 작업을 제어합니다.
  3. observe() 메서드를 사용하여 LiveData 객체에 Observer 객체를 연결합니다.
  4. LiveData 객체를 업데이트하는 경우 MutableLiveData 클래스는 setValue(T) 또는 postValue(T) 메서드로 LiveData 객체에 저장된 값을 수정합니다.

Room 🥉

Room 라이브러리는 SQLite에 추상화 레이어를 제공하여 원활한 DB 액세스를 지원하고 SQLite를 완벽히 활용할 수 있게 하는 라이브러리입니다.

Room 라이브러리 사용법

Room 라이브러리를 사용하면 앱을 실행하는 기기에서 앱 데이터의 캐시를 만들 수 있으며, 이 캐시를 통해 사용자는 인터넷 연결 여부와 관계없이 앱에 있는 주요 정보를 일관된 형태로 볼 수 있습니다.

📖 Reference

  1. Android 아키텍처 구성요소
  2. 앱 아키텍처 가이드
  3. ViewModel 개요
  4. LiveData 개요
  5. Room 지속성 라이브러리
profile
안드로이드 개발자를 꿈꾸는 사람

0개의 댓글