在 MVVM 的架構中我們經常要為了初始化需要傳入些參數進 ViewModel 而要寫 ViewModelFactory 例如下面這樣
class MainViewModelFactory(private val count: Int) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MainViewModel(count) as T
}
}
class MainViewModel(count: Int) : ViewModel() {
var title = MutableLiveData("title")
var count = MutableLiveData(count)
}
// in MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
mBinding.lifecycleOwner = this
mBinding.vm = ViewModelProviders.of(this, MainViewModelFactory(888)).get(MainViewModel::class.java)
}
但如果今天使用情境上 我們有個 ProfileActivity 依照目前是不需要初始的傳入值的
但是為了未來需求可能發生的變動 我也還是寫了 Factory
class ProfileViewModelFactory() : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return ProfileViewModel() as T
}
}
class ProfileViewModel() : ViewModel() {
var name = MutableLiveData("aki wang")
}
咦!! 這時我注意到為什麼每次我都要為了 xxxViewModel 額外再寫一個 xxxViewModelFactory 的 class
為了解決這問題 我們善用泛型解決這個問題 寫個通用的 ViewModelFactory 來用吧
class ViewModelFactory<T1 : ViewModel?>(private val listener: () -> T1? = { null } ) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return listener() as? T ?: modelClass.newInstance()
}
}
// in MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
mBinding.lifecycleOwner = this
// init view model
val viewModel = ViewModelProviders.of(this, ViewModelFactory{ MainViewModel(888) }).get(MainViewModel::class.java)
mBinding.vm = viewModel
// or
val viewModel2: MainViewModel by viewModels { ViewModelFactory { MainViewModel(888) } }
mBinding.vm = viewModel2
}
// in ProfileActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_profile)
mBinding.lifecycleOwner = this
// init view model
val viewModel = ViewModelProviders.of(this, ViewModelFactory() { ProfileViewModel() }).get(ProfileViewModel::class.java)
mBinding.vm = viewModel
// or
val viewModel2 = ViewModelProviders.of(this, ViewModelFactory<ProfileViewModel>()).get(ProfileViewModel::class.java)
mBinding.vm = viewModel2
// or
val viewModel3: ProfileViewModel by viewModels { ViewModelFactory { ProfileViewModel() } }
mBinding.vm = viewModel3
// or
val viewModel4: ProfileViewModel by viewModels()
mBinding.vm = viewModel4
}
這樣我們就可以 不用每次都要寫 Factory 啦~