MVVMとは?

![DALL·E 2023-12-11 16.55.44 - A visually appealing and informative thumbnail for a blog post about MVVM architecture in Android development. The image should feature a stylized and.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639815/fcef73f5-2aa4-affd-a37c-1bf50cee8555.png)


#  *MVVM パターン*
Model, View, ViewModel

MVVMパターンは、MVCパターンからコントロールラーを抜き、ViewModelを追加したパターン
それぞれの概念が独立的に存在し、テスト、メンテナンス、再利用が容易だが、設計するのが難しく、それでも慣れれば簡潔なコードでアンドロイドでもMVMを好むという。

* <span style="color:#FA5882">Model</span>  
-> データを意味するオブジェクト
                DataModelとも呼ばれ、DB、Network、共有Preferenceなど
さまざまなデータ ソースから必要なデータを用意する。
ViewModelからデータを取得できるようにデータを準備
</br>

* <span style="color:#FA5882">View</span>       :   xmlファイル -> 見せるもの
</br>

* <span style="color:#FA5882">ViewModel</span>  :   Viewを表現するために作ったViewのためのModel
                Viewを示すためのデータ処理担当
ViewとはBindingを行い、接続後にViewからアクションを受け、Viewをアップデートする
ex） textViewに表示する内容を担当する関数など、Viewで変化が起きるViewControllerの役割を担当

####  MVVMと主に一緒に使用される概念
<span style="color:#FA5882">
* DataBinding</br>
* LiveData / ViewModel</br>
* Android Di(Koin,Dagger) : Hilt依存性注入</span>

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にデータを要請して最新化する。
    <br/>
2. ViewとViewModelをバインディングするため、コードの量が減る
-> findViewId()で一つずつ与えることをしなくても良い
-> また、データを注入したり接続したりする作業をしなくてもよい。
(ViewがViewModelの値を見ていて自動更新されるためLive Dataで見るんだよね？）
        <br/>
3. Model、View、ViewModelの部分が独立しているため、モジュール化して開発することができる。
    MVC、MVPモデルの最終進化形態、それでアンドロイドが好むようだ<br/>

#### 短所 :
1.MVVMを作るのは難しいが慣れれば良いコード簡潔性になる
2.簡単なUIではむしろ面倒
3.複雑になるほど、コントロールラーのようにViewModelが急速に肥大化する。

or)

 AAC ViewModelとMVVMのViewModelは同じではない
 AAC ViewModelはViewModelProvidersを使ってViewModelを作る
 AAC ViewModelは、該当アクティビティに一つだけ存在する
 


# DataBinding
Viewにデータを入れる時、ActivityやFragmentで行うことをバインディングが処理してくれる<br/>
データをXml ですぐに使用できるため、Live Data と一緒に使用する。
    -> LiveDataと一緒に書くと、LiveDataのObserverを使う必要なく
       Dataが変更された時、すぐにXmlに反映させることができる。 <br/>(=LifeCycleOwner)<br/>
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
    -> Life Cycle を持っているため、Life Cycle の中でのみ動作する。<br/>
Observerオブジェクトを使用してLive Dataの中にデータアップデートを確認することができる。
    -> LifeCycle Ownerの値が変更されると自動的に値を更新してくれるため
       開発者が直接管理しなくてもよい。<br/>
DataBindingと一緒に使えば、Observerを使わずに簡単にViewの値を更新することができる。

LiveData おおよその構造 

```kotlin
 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データベースインスタンスが1つだけあればいいです。

```kotlin
@Database(entities = arrayOf(Word::class), version = 1, exportSchema = false)
public abstract class WordRoomDatabase : RoomDatabase() {

abstract fun wordDao(): WordDao

    companion object {
        
        @Volatile
        private var INSTANCE: WordRoomDatabase? = null
    
        fun getDatabase(context: Context): WordRoomDatabase {
            
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                        context.applicationContext,
                        WordRoomDatabase::class.java,
                        "word_database"
                    ).build()
                INSTANCE = instance
               
                instance
            }
        }
    }
}
```
- Roomのデータベースクラスは、```abstract```で、```RoomDatabase.```を拡張する必要があります。
- クラスをRoom データベースになるように ```@Database```で注釈処理し、注釈パラメータを使用してデータベースに属する項目を宣言し、バージョン番号を設定します。 各アイテムは、データベースに作成されるテーブルに相当します。 データベース移転はこのCodelabの範囲外なので、```exportSchema```はビルド警告を避けるためにfalseに設定しました。 実際のアプリでは、現在のスキーマをバージョン制御システムで確認できるように、スキーマをエクスポートするために使用するRoomディレクトリを設定することをお勧めします。
- 
- データベースは、各「Dao」の抽象「getter」メソッドを介してDAOを露出します。
- データベースの複数のインスタンスが同時に開くのを防ぐために、```WordRoomDatabase```をシングルトーンと定義

- ```getDatabase```はシングルトンを返します。 初めてアクセスするときにデータベースを作成し、Roomのデータベースビルダーを使用して ```WordRoomDatabase``` クラスのアプリケーション コンテキストで ```RoomDatabase``` オブジェクトを作成し、名前を ```"word_database"```と指定します。


</br>
</br>


参考

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