ViewModelFactory 懶人寫法


ViewModelFactory 懶人寫法

在 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 啦~


WRITTEN BY
Aki

熱愛寫code的開發者,專注於 Android 手機 Native App 開發,對於 IOS 也有涉略。閒暇之餘也學習 JavaScript 等前端框架