使用 androidx viewmodel 2.2.0 后,对 ViewModel 的创建有一些变化
原:ViewModelProviders.of(activity).get(ViewModel.class)
被替换为:ViewModelProvider(activity).get(ViewModel.class)
而使用 ViewModelProvider 创建继承自 AndroidViewModel 的类会报错 Cannot create an instance of class AndroidViewModel
原因是无法创建带参数的构造方法,原因是 ViewModelProvider 默认创建无参的构造方法,如果有参数的构造方法将无法正常创建。而 AndroidViewModel 需要使用带 application 参数的构造方法创建,解决办法是使用 AndroidViewModelFactory 创建 AndroidViewModel。如下
ViewModelProvider(
activity,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)
).get(ViewModel.class)
如果你需要创建更多参数的构造方法,需要自定义 AndroidViewModelFactory,如下是多了一个 String 型的AndroidViewModelFactory
class AndroidViewModelFactory private constructor(
private val mApplication: Application,
private val mName: String
) : ViewModelProvider.NewInstanceFactory() {
override fun create(modelClass: Class): T {
return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
try {
modelClass.getConstructor(
Application::class.java, String::class.java
).newInstance(mApplication, mName)
} catch (e: Exception) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
} else super.create(modelClass)
}
companion object {
private var sInstance: AndroidViewModelFactory? = null
fun getInstance(
application: Application,
name: String
): AndroidViewModelFactory {
if (sInstance == null) {
sInstance = AndroidViewModelFactory(application, name)
}
return sInstance as AndroidViewModelFactory
}
}
}
使用方式如下
ViewModelProvider(
activity,
AndroidViewModelFactory.getInstance(application, name)
).get(ViewModel.class)
另附上我创建 ViewModel 的方式
1.AndroidViewModelFactory
class AndroidViewModelFactory private constructor(
private val mApplication: Application,
private val mName: String
) : ViewModelProvider.NewInstanceFactory() {
override fun create(modelClass: Class): T {
return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
try {
modelClass.getConstructor(
Application::class.java, String::class.java
).newInstance(mApplication, mName)
} catch (e: Exception) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
} else super.create(modelClass)
}
companion object {
private var sInstance: AndroidViewModelFactory? = null
fun getInstance(
application: Application,
name: String
): AndroidViewModelFactory {
if (sInstance == null) {
sInstance = AndroidViewModelFactory(application, name)
}
return sInstance as AndroidViewModelFactory
}
}
}
2.ViewModelFactory
/**
* @author: Eli Shaw
* @Date: 2020-04-27 17:20:45
* @Description:创建相应的 ViewModel
*/
object ViewModelFactory {
/**
* @Description: 创建 FragmentActivity 页面的 ViewModel
* @Author: Eli
* @Date: 2020-05-09 14:41:04
*/
fun createViewModel(
activity: FragmentActivity,
cls: Class?
): T {
return ViewModelProvider(activity).get(cls!!)
}
/**
* @Description: 创建 Fragment 页面的 ViewModel
* @Author: Eli
* @Date: 2020-05-09 14:40:36
*/
fun createViewModel(
fragment: Fragment,
cls: Class?
): T {
return ViewModelProvider(fragment).get(cls!!)
}
/**
* @Description:创建 FragmentActivity 页面的 AndroidViewModel
* @Author: Eli
* @Date: 2020-05-09 14:36:39
*/
fun createViewModel(
activity: FragmentActivity,
application: Application,
cls: Class?
): T {
return ViewModelProvider(
activity,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)
).get(cls!!)
}
/**
* @Description:创建 Fragment 页面的 AndroidViewModel
* @Author: Eli
* @Date: 2020-05-09 14:36:39
*/
fun createViewModel(
fragment: Fragment,
application: Application,
cls: Class?
): T {
return ViewModelProvider(
fragment,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)
).get(cls!!)
}
/**
* @Description: 创建带参数的 AndroidViewModel
* @Author: Eli
* @Date: 2020-05-09 14:36:24
*/
fun createViewModel(
activity: FragmentActivity,
application: Application,
name: String,
cls: Class?
): T {
return ViewModelProvider(
activity,
AndroidViewModelFactory.getInstance(application, name)
).get(cls!!)
}
}
3.NameViewModel
class NameViewModel(application: Application, name: String) : AndroidViewModel(application) {
val name = ObservableField()
init {
this.name.set(name)
}
}
4.NameActivity
class NameActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding =
DataBindingUtil.setContentView(this, R.layout.activity_name) as ActivityNameBinding
val viewModel = ViewModelFactory.createViewModel(
this,
application,
"AndroidViewModel",
NameViewModel::class.java
)
binding.viewModel = viewModel
}
}
5.activity_name