MVVM 架構是繼mvc架構後衍生出的一個新的架構, 最先於 2005 年被微軟的 WPF 和 Silverlight 的架構師 John Gossman 提出,而且應用在微軟的軟件開發中,Android開發中常見的模式,有 MVC,MVP,MVVM。Google15年推出databinding 和 2018年推出 LiveData、ViewModel 庫以後,把MVVM正式的應用在 android 上 推動了高潮。本文最後會寫一個官方所支持的demophp
備註:摘自任玉剛公衆號的一篇文章java
題外話:1.項目中不必定用LiveData,Rxjava自己就是觀察者模式,若是項目中引用到Rxjava,能夠拋棄LiveData,可是請確保正確處理應用的生命週期。特別是,確保在相關的 LifecycleOwner 中止時暫停數據流,並在相關的 LifecycleOwner 銷燬時銷燬這些數據流。官方說法android
題外話:2.MVVM能夠不用DataBinding,可是android中Google既然已經支持,仍是用DataBinding來處理View的更改,在android中 DataBinding 是實現MVVM的主要組件git
在應用模塊的 build.gradle 文件中添加 dataBinding 元素github
android {
...
dataBinding {
enabled = true
}
}
複製代碼
以後你在xml的根佈局中 ,mac按住command+return ,window 按住 art+enter 就會出現這樣的標記,選第一個就會出現DataBinding的layout。若是沒有這個選項,重啓studio就能夠了 數據庫
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
複製代碼
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
複製代碼
使用方式bash
val user: LiveData<User> = liveData {
val data = getNetData() // loadUser is a suspend function.
emit(data) //發射給出去
}
複製代碼
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
複製代碼
會用方式服務器
class MainViewModel(private val repository: MainUserRepository) : ViewModel() {
var userData = MutableLiveData<User>()
var progressShow = MutableLiveData<Boolean>()
fun click(view: View) {
getUser()
}
private fun getUser() {
//在這裏開協程
viewModelScope.launch {
progressShow.value = true
userData.value = repository.getUser()
progressShow.value = false
}
}
}
複製代碼
implementation "androidx.activity:activity-ktx:1.1.0"
複製代碼
使用方式:直接在acitiviy中調用下面的方法,另外這個還須要在app的build.gradle中加入一個配置。固然了,咱們也能夠用別的懶加載方式加載ViewModel,就能夠不用引用這個依賴了,好比網絡
//不用添加此依賴的方式獲取懶加載ViewModel
val viewModel:MyViewModel by lazy { ViewModelProvider(this).get(MyViewModel::class.java) }
複製代碼
//使用此依賴須要配置
android {
kotlinOptions {
jvmTarget = "1.8"
}
...
}
複製代碼
// 這裏只能用val來修飾
private val viewModel: MyViewModel by viewModels ()
複製代碼
implementation "androidx.fragment:fragment-ktx:1.2.4"
複製代碼
使用方式架構
private val viewModel : MyViewModel by viewModels()
複製代碼
數據類
data class User(var name:String,var age:Int)
複製代碼
UesrActivity
class UserActivity : AppCompatActivity() {
//建立ViewModel方式1
// private val viewModel: UserViewModel by viewModels()
//建立ViewModel方式2
// private val viewModel:UserViewModel by lazy { ViewModelProvider(this).get(UserViewModel::class.java) }
private val viewModel: UserViewModel by viewModels {
// 經過InjectorUtils類拿到對應的ViewModelFactory,這種方法能夠定義構造方法帶參的ViewModel
InjectorUtils.provideUserViewModelFactory()
}
private var progressDialog: ProgressDialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var binding =
DataBindingUtil.setContentView<ActivityUserBinding>(this, R.layout.activity_user)
//綁定生命週期,聲明這個 Activity 爲 Data Binding 的 lifecycleOwner
binding.lifecycleOwner = this
//設置xml中的viewModel
binding.viewmodel = viewModel
// viewModel的progressShow 來判斷是不是加載中的狀態
viewModel.progressShow.observe(this, Observer<Boolean> {
if (it) showLoading()
else stopLoading()
})
}
/** * 顯示加載框 */
private fun showLoading() {
if (progressDialog == null) {
progressDialog = ProgressDialog(this)
progressDialog!!.setMessage("加載中")
}
progressDialog!!.show()
}
/** * 關閉加載框 */
private fun stopLoading() {
progressDialog?.dismiss()
}
companion object {
fun startMe(activity: Activity) {
activity.startActivity(Intent(activity, UserActivity::class.java))
}
}
}
複製代碼
activity_user.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools">
<data>
<!-- 引入User的model-->
<variable name="viewmodel" type="com.nzy.mvvmsimple.user.UserViewModel" />
<!-- View ,可使用 View.GONE 和 View.VISIBLE -->
<import type="android.view.View" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">
<TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewmodel.userData.name}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" />
<Button android:id="@+id/bv_get_user" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:onClick="@{viewmodel::click}" android:text="獲取網絡數據" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_name" />
<ProgressBar android:layout_width="50dp" android:layout_height="50dp" android:visibility="@{viewmodel.progressShow ? View.VISIBLE : View.GONE}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
複製代碼
InjectorUtils類:用來獲取各類各樣的ViewModelFatory
object InjectorUtils {
fun provideUserViewModelFactory(): UserViewModelFactory {
val repository = getUserRepository()
return UserViewModelFactory(repository)
}
private fun getUserRepository(): UserRepository {
return UserRepository.getInstance()
}
}
複製代碼
UserViewModelFactory
class UserViewModelFactory(
private val repository: UserRepository
) : ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
// 傳入一個 Repository 參數
return UserViewModel(repository) as T
}
}
複製代碼
UserRepository:獲取數據的網絡或者數據庫
/** * 獲取用戶信息的Repository */
class UserRepository private constructor() {
/** * 獲取User的接口 */
suspend fun getUser(): User? {
delay(3000)
return User("王者榮耀之馬大黑", 18)
}
companion object {
// For Singleton instantiation
@Volatile
private var instance: UserRepository? = null
fun getInstance() =
instance ?: synchronized(this) {
instance ?: UserRepository().also { instance = it }
}
}
}
複製代碼