#記事を移動しました。
https://zenn.dev/dd_sho/articles/5f32ce2942cbd2
今後は上記の記事で更新します。(2021/10/03)
Googleが推奨する MVVM
について調べてみたのでまとめます。
MVVMを採用したサンプルプロジェクトのコードをこちらに挙げています。
この記事の後ろの方に一部抜粋してコードを載せていますが全体のコードが気になる方は参照してください。
MVVMの概要
MVVMの概要を図にするとこんな感じでしょうか。
MVVMを構成する要素はView、ViewModel、Modelの3つです。
(Repositoryは必須ではない)
各要素の役割
View
-
UIの更新
データ処理の結果を画面に表示する、画面遷移、Fragmentの切り替え、etc... -
ユーザのアクションを検知する
ボタンのクリック、リストのスクロール、etc...
ViewModel
- Modelからデータを取得する(Repository経由で取得することもある)
- 取得したデータをViewで表示するための処理を行う
Model
- データを管理する
Repository
- ViewModelとModelを疎結合にする(必須ではない)
View、ViewModel、Modelで実装すること
それぞれの役割を果たすために以下の内容を実装する
View
ViewModelのインスタンスを保持して
-
ViewModelのデータ処理を行うメソッドを呼ぶ
ボタンがタップされたらviewModel.loadData()を呼ぶ、etc... -
ViewModelのLiveDataプロパティを監視する
-
①ソースコードで監視する
viewModel.sampleLiveData.observe(this, Observer { 更新された時の処理 })、etc... -
②DataBindingでxmlファイルから監視する
※LiveDataについてはこちら
ざっくり言うとViewのライフサイクルを考慮してくれるObservable
※DataBindingについてはこちら
ViewModel
Model(or Repository)のインスタンスを保持して
-
データ処理を行うメソッドを定義する(Viewから呼ばれる)
loadData()、updateStatus()、etc... -
Viewにデータを渡すためのLiveDataプロパティを定義する(Viewから監視される)
-
Model(or Repository)のデータを取得するメソッドを呼ぶ
データ処理メソッドが呼ばれたらmodel.fetchData()を呼ぶ、etc... -
取得したデータをViewで表示するために処理を行うメソッドを定義する(必要に応じて)
model.fetchData()で取得したデータの内Viewが必要な値だけ取り出して
LiveDataプロパティを更新する、etc...
Model
-
実際にデータが保存されている場所へのアクセスを管理するクラスを用意する
APIClient、Dao、etc... -
アプリ内でデータを扱いやすくする独自のデータクラスを定義する
idとnameプロパティを持ったUserクラス、etc...
Repository(実装しない場合はModel)
-
実際にデータが保存されている場所に直接アクセスするクラスを用意する
API、DB、Preference、etc... -
必要に応じて、追加/取得/更新/削除を行うメソッドを実装する
実装例
全体のコードはこちらを参照してください。
View
class MainFragment : Fragment() {
private val viewModel: MainViewModel by sharedViewModel()
// 省略
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
binding.apply {
viewmodel = viewModel // xml内でDataBindingの変数としてviewmodelを定義
setLifecycleOwner(activity)
}
viewModel.initParameters() // 初期表示時のデータ処理
observeViewModel() // MainViewModelのLiveDataプロパティを監視する
}
private fun observeViewModel() {
viewModel.playStatus.observe(this, Observer {
// 省略
})
viewModel.themePicFileResId.observe(this, Observer {
// 省略
})
}
// 省略
}
ViewModel
class MainViewModel(val context: Application)
: AndroidViewModel(context), KoinComponent {
var themePicFileResId = MutableLiveData<Int>() // LiveDataのプロパティ
var playStatus = MutableLiveData<Int>() // LiveDataのプロパティ
// 省略
private val userSettingsRepository: UserSettingsRepository by inject()
private lateinit var userSettings: UserSettings // 独自のデータクラス(Model)
// 初期表示時のデータ処理
fun initParameters() {
userSettings = userSettingsRepository.loadUserSettings() // データ取得
themePicFileResId.value = userSettings.themeResId // 更新してViewに通知
playStatus.value = PlayStatus.BEFORE_START // 更新してViewに通知
}
// 省略
}
Model
data class UserSettings(
var levelId: Int,
var levelName: String,
// 省略
var themeResId: Int) {
// 省略
}
Repository
class UserSettingsRepository {
private val context = MyApplication.appContext
private val pref = context.getSharedPreferences(UserSettings.PREF_USERSETTINGS_NAME, Context.MODE_PRIVATE) // SharedPreferenceのインスタンス
// SharedPreferenceからデータを取得
fun loadUserSettings(): UserSettings {
// 省略
}
}
まとめ
Androidの MVVM についてサンプルプロジェクトを作成してまとめてみました。
誤っている点などご指摘いただけますと助かります。