错误示例
话不多说,直接上代码
abstract class BaseAct<T:BaseViewModel> :AppCompatActivity(){
protected lateinit var mActivity:AppCompatActivity
protected lateinit var mContext: Context
protected lateinit var mViewModel: T
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(getLayoutViewId())
mActivity = this
mContext = this
mViewModel = ViewModelProvider(this,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)).get(T::class.java)
onCreated(savedInstanceState)
}
abstract fun getLayoutViewId():Int
abstract fun onCreated(savedInstanceState: Bundle?)
}
以上代码中,我想去创建一个泛型ViewModel的实例,然后报错:
Kotlin get type of generic class without instance
这样中时不行的因为,具体的实例kotlin不能知道是什么对象,这里需要利用反射。
参考了代码:
/**
* 创建 ViewModel
*/
@Suppress("UNCHECKED_CAST")
private fun createViewModel() {
//这儿为啥要用反射 我的理解是反射取出viewModel超类 判断是否是BaseViewModel,ParameterizedType这个是参数化泛型
val type = javaClass.genericSuperclass
if (type is ParameterizedType) {
val tp = type.actualTypeArguments[0]
val tClass = tp as? Class<VM> ?: BaseViewModel::class.java
//你问我为啥要用工厂,我刚开始也不知道,后来在csdn上看别人的学习资料的时候才知道 ViewModelProviders.of new对象创建,已经被弃用了
viewModel = ViewModelProvider(this, ViewModelFactory()).get(tClass) as VM
}
}
Kotlin的反思:未知的类型参数 获取方式
“androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0”
注意这里创建viewmodel的方式,ViewModelProvider.of方式在2.2.0已舍弃
最后看一下我的项目damo
代码实例
创建BaseViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
open class BaseViewModel : ViewModel(){
var mutableLiveData:MutableLiveData<String> = MutableLiveData()
fun launch(mutableLiveData:MutableLiveData<String>,block:()->Unit){
viewModelScope.launch {
block()
mutableLiveData.value = "wpf"
}
}
}
创建BaseActivity
import android.content.Context
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import java.lang.reflect.ParameterizedType
abstract class BaseAct<T:BaseViewModel> :AppCompatActivity(){
protected lateinit var mActivity:AppCompatActivity
protected lateinit var mContext: Context
protected lateinit var mViewModel: T
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(getLayoutViewId())
mActivity = this
mContext = this
/*利用反射获取类实例*/
val persistentClass = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
mViewModel = ViewModelProvider(this,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)).get(persistentClass)
onCreated(savedInstanceState)
}
abstract fun getLayoutViewId():Int
abstract fun onCreated(savedInstanceState: Bundle?)
}
具体ViewModel实例
import android.util.Log
import com.wpf.common_module.BaseViewModel
class TestViewModel :BaseViewModel() {
fun doThing(){
Log.e("wpf","TestViewModel")
}
}
使用
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.lifecycle.Observer
import com.wpf.common_module.BaseAct
import com.wpf.studywork.R
class TestAct : BaseAct<TestViewModel>() {
override fun getLayoutViewId(): Int= R.layout.activity_test
override fun onCreated(savedInstanceState: Bundle?) {
var testViewModel:TextView = findViewById(R.id.textView)
testViewModel.setOnClickListener {
mViewModel.launch(mViewModel.mutableLiveData){
Log.e("wpf","123")
}
mViewModel.doThing()
}
mViewModel.mutableLiveData.observe(this, Observer{
Log.e("wpf","::::$it")
})
}
}
这里使用的好处是,任何你继承BaseViewModel的类,都可以使用其方法,也可以自己定义方法,快捷方便。