MVVM란?

KIMGEUNTAE·2022년 11월 7일
1
post-thumbnail

MVVM 패턴

Model, View, ViewModel의 약자

MVVM 패턴은 MVC 패턴에서 Controller를 빼고 ViewModel을 추가한 패턴
각각의 개념들이 독립적으로 존재해서 테스트, 유지 보수, 재사용이 쉽지만 설계하는 것이 어려움 그래도 익숙해지면 간결한 코드로 안드로이드에서도 MVVM을 선호 한다고 함.

  • Model
    -> 데이터를 의미하는 객체
    DataModel이라고도 하며 DB, Network, SharedPreference 등
    다양한 데이터 소스로부터 필요한 데이터를 준비함.
    ViewModel에서 데이터를 가져갈 수 있게 데이터를 준비

  • View : xml 파일 -> 보여주는 것

  • ViewModel : View를 표현하기 위해 만든 View를 위한 Model
    View를 나타내주기 위한 데이터 처리담당
    View와는 Binding을 하여 연결후 View에게서 액션을 받고 또한 View를 업데이트한다
    ex) textView에 보여줄 내용을 담당하는 함수 등, View에서 변화가 일어나는 ViewController의 역할을 담당

MVVM과 주로 함께 사용되는 개념

* DataBinding
* LiveData / ViewModel
* Android Di(Koin,Dagger) : Hilt 의존성 주입

View는 ViewModel을 알지만 ViewModel은 View를 알지 못하고,
ViewModel은 Model을 알지만 Model은 ViewModel을 알지못한다.
즉, 한쪽 방향으로만 의존 관계가 있으므로 각 모듈별로 분리하여 개발 할 수 있다.
Repositroy를 사용하여 알지를 못하게 하는 것 거치게 하는 것

  1. View에 입력이 들어오면 ViewModel에게 명령을 함.

  2. ViewModel은 필요한 데이터를 Model에게 요청

  3. Model은 ViewModel에게 요청된 데이터를 응답

  4. ViewModel은 응답 받은 데이터를 가공해서 저장합니다

  5. View는 ViewModel과의 Data Binding으로 인해 자동으로 갱신

장점 :

  1. View와 Model사이의 의존성이 없다.
    -> View는 ViewModel의 데이터만 바라보고 있고, ViewModel이 Model에게 데이터를 요청하고 최신화한다.
  2. View와 ViewModel을 바인딩하기 때문에 코드의 양이 줄어든다
    -> findViewId()로 하나씩 일일히 주는 것을 안해도 됨
    -> 또한 데이터를 주입하거나 연결하던 작업을 하지 않아도 된다.
    (View가 ViewModel의 값을 보고 있어서 자동 갱신되기 때문
    LiveData로 보는 거겠지?)
  3. Model , View , ViewModel 부분 부분이 독립적이기 때문에 모듈화 하여 개발할 수 있다.
    -> MVC , MVP 모델의 최종 진화형태 그래서 안드로이드가 선호 하는듯

단점 :

1.MVVM 만드는 것은 어렵지만 익숙해지면 좋은 코드 간결성이 됨
2.간단한 UI에서는 오히려 번거로움
3.복잡해질수록 Controller처럼 ViewModel이 빠르게 비대해진다.

or)
AAC ViewModel과 MVVM의 ViewModel은 같지 않음
AAC ViewModel은 ViewModelProviders를 사용해서 ViewModel을 만듬
AAC ViewModel은 해당 액티비티에서 딱 하나만 존재하게 됨

DataBinding

View에 데이터를 넣을때 Activity나 Fragment에서 하는 걸 바인딩이 처리해줌

데이터를 Xml에서 바로 사용가능하기 때문에 LiveData와 함께 쓰인다.
-> LiveData와 함께 쓰게되면 LiveData의 Observer를 사용할 필요없이
Data가 변경될 때 바로 Xml에 반영시킬 수 있다.
(=LifeCycleOwner)

BindingAdapter를 사용하면 View에 관련된 코드(RecyclerView, Glide , View로직)를
Activity, Fragment에서 코드를 분리 하고 가독성이 좋아짐

View의 데이터를 Activity에서 세팅하는게 아니라 xml에서 ViewModel의 값을 직접 가져오는 방법

-> Activity에는 로직만을 위한 코드만 남고, View와 관련된 작업은 xml파일에 정의된다.
-> DataBinding = Data와 View를 연결하는 작업을 레이아웃(xml)에서 처리하는 기술

xml파일 구조

<layout>
    <data>
        <variable
            name=""  //xml에서 사용할 변수명
            type=""/> //클래스 및 함수 파일 경로
        ...
    </data>
</layout>

LiveData

안드로이드 LifeCycle을 가지고 있는 DataType
-> LifeCycle을 가지고 있어서 LifeCycle안에서만 동작한다.

Observer 객체를 사용해서 LiveData안에 Data업데이트를 확인할 수 있다.
-> LifeCycleOwner가 값이 변경되면 자동으로 값을 갱신해주기 때문에
개발자가 직접 관리하지 않아도 된다.

DataBinding과 함께 쓰게 된다면 Observer를 사용하지않고 손쉽게 View의 값을 갱신할 수 있다.

LiveData 대략 구조

 val getAllData: LiveData<List<Write>> = repository.getAllData.asLiveData()

ViewModel

ViewModel을 사용하는 이유는 UI와 로직의 분리이다.
Activity와 Fragment는 UI를 업데이트 하는데만 집중할 수 있고, ViewModel에 있는 데이터는 Activity와 Fragment의 수명주기로부터 자유로워진다.
따라서 UI와 데이터 처리 로직을 분리시키면 유지보수와 개발 효율이 높아지는 것이다.
또한 ViewModel에 있는 데이터는 마치 Sington 객체 처럼 사용이 가능해서 Fragment 사이에서 ViewModel을 이용해 데이터를 쉽게 공유할 수 있다.

Room

Room은 SQLite 데이터베이스 위에 있는 데이터베이스로 SQLite의 단점을 보완한 것
Room은 개발자가 SQLiteOpenHelper를 사용하여 처리하던 일반적인 작업을 처리합니다.
Room은 DAO를 사용하여 데이터베이스에 쿼리를 실행합니다.
기본적으로 UI 성능 저하를 방지하기 위해 Room에서는 기본 스레드에서 쿼리를 실행할 수 없으며 Room 쿼리가 Flow를 반환하면 쿼리는 자동으로 백그라운드 스레드에서 비동기식으로 실행됩니다.
Room은 SQLite 문의 컴파일 시간 확인을 제공

Room 데이터베이스 클래스는 추상 클래스이고 RoomDatabase를 확장해야 합니다. 일반적으로 전체 앱에 Room 데이터베이스 인스턴스가 하나만 있으면 됩니다.

// Annotates class to be a Room Database with a table (entity) of the Word class
@Database(entities = arrayOf(Word::class), version = 1, exportSchema = false)
public abstract class WordRoomDatabase : RoomDatabase() {

   abstract fun wordDao(): WordDao

   companion object {
        // Singleton prevents multiple instances of database opening at the
        // same time.
        @Volatile
        private var INSTANCE: WordRoomDatabase? = null

        fun getDatabase(context: Context): WordRoomDatabase {
            // if the INSTANCE is not null, then return it,
            // if it is, then create the database
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                        context.applicationContext,
                        WordRoomDatabase::class.java,
                        "word_database"
                    ).build()
                INSTANCE = instance
                // return instance
                instance
            }
        }
   }
}
  • Room의 데이터베이스 클래스는 abstract이고 RoomDatabase.를 확장해야 합니다.

  • 클래스를 Room 데이터베이스가 되도록 @Database로 주석 처리하고 주석 매개변수를 사용하여 데이터베이스에 속한 항목을 선언하고 버전 번호를 설정합니다. 각 항목은 데이터베이스에 만들어질 테이블에 상응합니다. 데이터베이스 이전은 이 Codelab의 범위를 벗어나므로 exportSchema는 빌드 경고를 피하기 위해 false로 설정했습니다. 실제 앱에서는 현재 스키마를 버전 제어 시스템으로 확인할 수 있도록 스키마를 내보내는 데 사용할 Room 디렉터리를 설정하는 것이 좋습니다.

  • 데이터베이스는 각 @Dao의 추상 'getter' 메서드를 통해 DAO를 노출합니다.

  • 데이터베이스의 여러 인스턴스가 동시에 열리는 것을 막기 위해 WordRoomDatabase,를 싱글톤으로 정의

  • getDatabase는 싱글톤을 반환합니다. 처음 액세스할 때 데이터베이스를 만들어 Room의 데이터베이스 빌더를 사용하여 WordRoomDatabase 클래스의 애플리케이션 컨텍스트에서 RoomDatabase 객체를 만들고 이름을 "word_database"로 지정합니다.

참고
https://jhtop0419.tistory.com/m/21
https://kangmin1012.tistory.com/16?category=879935
https://kangmin1012.tistory.com/18?category=879935
https://velog.io/@mingyun12304/Android-KotlinViewModel-LiveData
https://aonee.tistory.com/48
https://developer.android.com/codelabs/android-room-with-a-view-kotlin?hl=ko#0
https://tech.nri-net.com/entry/mvvm_in_android

profile
Study Note

0개의 댓글