多ViewModel场景封装BaseActivity时ViewModelProvider.get方法报错求解
多ViewModel Activity基类报错修复方案
问题根因
- 泛型参数不匹配:代码中调用
ViewModelProvider.get时硬指定了泛型为ViewModel,但传入的参数是Class<VM>类型,二者类型不一致触发编译器校验报错 - 原有泛型设计缺陷:当前基类仅定义了单个
VM泛型约束,若需要使用多个不同类型的ViewModel,该约束会要求所有ViewModel继承自同一个子类,不符合多ViewModel的使用场景
修复代码
方案1:支持任意多个不同类型的ViewModel(推荐适配你的需求)
abstract class BaseActivity<B : ViewBinding>(val bindingFactory: (LayoutInflater) -> B) : AppCompatActivity() { protected val binding: B by lazy { bindingFactory(layoutInflater) } // 存储所有初始化后的ViewModel protected val viewModels = arrayListOf<ViewModel>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) } // 内联reified泛型函数,调用时直接传入ViewModel类即可自动完成初始化 protected inline fun <reified VM : ViewModel> initViewModel(): VM { val vm = ViewModelProvider(this)[VM::class.java] viewModels.add(vm) return vm } }
使用示例
// 子类Activity使用方式 class MyActivity : BaseActivity<ActivityMyBinding>(ActivityMyBinding::inflate) { // 直接初始化两个不同类型的ViewModel private val firstVm: FirstViewModel by lazy { initViewModel() } private val secondVm: SecondViewModel by lazy { initViewModel() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 后续直接使用两个ViewModel即可 } }
方案2:兼容你原有List传参的写法
如果一定要保留构造函数传入ViewModel Class列表的写法,修改如下即可解决报错:
abstract class BaseActivity<B : ViewBinding, VM : ViewModel>( val bindingFactory: (LayoutInflater) -> B, private val vmClassList: List<Class<VM>> ) : AppCompatActivity() { protected val binding: B by lazy { bindingFactory(layoutInflater) } protected val viewModels = arrayListOf<VM>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) vmClassList.forEach { vmClass -> // 把get的泛型改为VM,和传入的class类型匹配即可消除报错 viewModels.add(ViewModelProvider(this).get(vmClass)) } setContentView(binding.root) } }
内容的提问来源于stack exchange,提问作者Pemba Tamang
相关产品推荐
相关产品推荐

