Android 공부/앱 디자인 패턴
MVVM
posite
2026. 2. 22. 15:03
MVVM
- 소프트웨어를 Model - View - ViewModel로 구분하여 개발하는 패턴
- 각각의 역할은 다음과 같다
- Model : 데이터, 도메인 로직, DB 구조 등
- View : 사용자가 보거나 상호작용 하는 화면 (Layout, UI 구성 요소)
- ViewModel : View의 상태 관리 및 로직을 위한 Model - 데이터 바인딩을 통해 View에 최신 데이터 제공
- DataBinding을 통해 View가 ViewModel를 관찰하여 화면 갱신
- ViewModel은 View를 모르며, Model은 View, ViewModel을 모름
->의존성 분리를 통해 화면이 바뀌어도 데이터 로직에 영향을 받지 않음 -> 유지보수성 향상 - 설계가 어려워 간단한 앱에는 비효율적
- 과도한 데이터 바인딩 사용 혹은 Observation 관리를 제대로 하지 않으면 메모리 누수 발생 가능
예시)
Model : 데이터를 정의하고 가져오는 역할 - DB, 네트워크 통신 데이터를 가져오는 코드
// 1. 데이터 클래스 (단순한 데이터 덩어리)
data class User(val name: String, val age: Int)
// 2. 데이터 저장소 (데이터를 가져오는 로직)
class UserRepository {
fun fetchUserData(): User {
// 실제로는 서버 통신을 하겠지만, 예시를 위해 바로 반환합니다.
return User("posite", 28)
}
}
ViewModel : Model에서 요청 및 받아온 데이터를 가공
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class UserViewModel : ViewModel() {
private val repository = UserRepository()
// View가 관찰(Observe)할 데이터 (LiveData)
private val _userData = MutableLiveData<User>()
val userData : LiveData<User> = _userData
fun loadUser() {
// 데이터가 바뀌었다고 '알림'을 보냄
_userData.value = repository.fetchUserData()
}
}
XML : ViewModel의 데이터를 관찰하다가 변화가 생기면 화면 갱신 및 ViewModel에 데이터 요청
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="vm"
type="com.example.app.UserViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`이름: ` + vm.userData.name}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`나이: ` + String.valueOf(vm.userData.age)}" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="사용자 불러오기"
android:onClick="@{() -> vm.loadUser()}" />
</LinearLayout>
</layout>
View : Observe 할 필요 없이 ViewModel만 넘기면 됨
class UserActivity : AppCompatActivity() {
private lateinit var binding: ActivityUserBinding // 자동 생성된 바인딩 클래스
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 1. 바인딩 객체 생성
binding = DataBindingUtil.setContentView(this, R.layout.activity_user)
val viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
// 2. XML의 변수(vm)와 실제 ViewModel 연결
binding.vm = viewModel
// 3. LiveData가 변할 때 XML이 알아차리도록 생명주기 주인 설정
binding.lifecycleOwner = this
}
}