###### tags: `Android`
# MVVM 架構
在學習 MVVM 之前,可以先觀看 [Android 三種開發架構,MVC、MVP、MVVM怎麼選?](https://www.youtube.com/watch?v=nViX8m7gS7I) 來認識除了 MVVM 之外還有哪些架構,以及為什麼我們應該選擇使用 MVVM 架構。
Model:管理資料來源,如 Web API、本地資料庫
View:顯示 UI 和接收使用者動作
ViewModel:接收 View 的指令,並從 Model 取得 View 所需的資料
## 建立基本的 MVVM
建立 Model:==DataModel==
```kotlin=
class DataModel {
interface onDataReadyCallback {
fun onDataReady(data: String)
}
//模擬資料獲取時的延遲
fun retrieveData(callback: onDataReadyCallback) {
Handler().postDelayed({
callback.onDataReady("New Data")
}, 1000)
}
}
```
建立 ViewModel:==MainViewModel==
```kotlin=
class MainViewModel {
private val dataModel = DataModel()
fun refresh() {
dataModel.retrieveData(object : DataModel.onDataReadyCallback {
override fun onDataReady(data: String) {
//TODO("Use observable to update UI")
}
})
}
}
```
建立 View:==MainActivity、activty_main==
```kotlin=
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = MainViewModel()
btn_refresh.setOnClickListener {
viewModel.refresh()
}
}
}
```
```xml=
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Refresh"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
```
這樣就完成基本的 MVVM 架構,剩下的就是 View 如何接收資料並更新 UI
而這個部分會使用 Data Binding 來完成 View 與 ViewModel 的溝通。
==為什麼要使用 Data Binding?==
MVVM 是使用觀察者的方式達成,以前有人會自己寫觀察者模式來處理
但有了 ObservableField 後就省事很多,而在 Android 發展出 Data Binding 後
也將原本的 ObservableField 納入 Data Binding 函式庫中。
## Jetpack Data Binding
Data Binding 可以看[此篇教學](https://hackmd.io/USJfeNs2R1qLGp6rkEJQiw)
## Jetpack ViewModel
完成 DataBinding 後,目前的架構還需要處理生命週期問題,如螢幕旋轉後資料遺失,而 Jetpack 的 ViewModel 能解決這問題,它有 lifecycle-aware 的特性,不會因 Activity 被重建而清除,在每次重建都能持有相同實體。
ViewModel 可以看[此篇教學](https://hackmd.io/ROW4JBjqRTOrwLDltAeZDQ)
## Jetpack LiveData
由於 Data Binding 沒有 Lifecycle-aware 的特性,因此 View 在背景時仍會觸發更新,而 Jetpack 的 LiveData 能解決這問題,它有 lifecycle-aware 的特性,能確保 Activity、Fragment 只在活耀的狀態才會收到資料的變化。
LiveData 可以看[此篇教學](https://hackmd.io/Peh0693lSQSjpvBzjaMcIg?view)