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
    }
}