如何在Kotlin Android中实现支持多ViewModel的通用ViewModelFactory?
精简统一ViewModelFactory的实现方案
以下两种方案都可以大幅减少现有代码的冗余逻辑:
方案1:无反射映射表实现(推荐)
这种方案不需要修改原有业务代码,仅对Factory内部的判断逻辑做结构化改造:
class AppViewModelFactory : ViewModelProvider.Factory { // 维护ViewModel类和实例创建逻辑的映射关系 private val viewModelCreators = mapOf<Class<out ViewModel>, () -> ViewModel>( LoginViewModel::class.java to { LoginViewModel(LoginRepository(LoginDataSource())) }, UserViewModel::class.java to { UserViewModel(UserRepository(UserDataSource())) }, TransactionViewModel::class.java to { TransactionViewModel(TransactionRepository(TransactionDataSource())) } ) @Suppress("UNCHECKED_CAST") override fun <T : ViewModel> create(modelClass: Class<T>): T { val creator = viewModelCreators[modelClass] ?: viewModelCreators.entries.firstOrNull { modelClass.isAssignableFrom(it.key) }?.value ?: throw IllegalArgumentException("未找到匹配的ViewModel类:$modelClass") return creator() as T } }
该方案的优势:
- 无反射性能损耗,运行效率和原有if判断写法完全一致
- 后续新增ViewModel仅需在
viewModelCreators映射表中新增一行配置即可,无需新增if判断,代码结构更清晰 - 支持任意构造参数的ViewModel,实例化逻辑和原有写法完全兼容
方案2:反射通用实现(适合构造规则统一的场景)
如果你的所有ViewModel、Repository、DataSource的构造参数规则完全统一(比如ViewModel仅接收对应Repository作为参数,Repository仅接收对应DataSource作为参数),可以用反射实现完全自动适配,后续新增ViewModel无需修改Factory代码:
class AppViewModelFactory : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST", "RemoveExplicitTypeArguments") override fun <T : ViewModel> create(modelClass: Class<T>): T { return try { // 取ViewModel的第一个构造函数 val vmConstructor = modelClass.constructors.first() // 取构造函数第一个参数的类型(即对应Repository的类) val repoClazz = vmConstructor.parameterTypes[0] val repoConstructor = repoClazz.constructors.first() // 取Repository构造的第一个参数类型(即对应DataSource的类) val dsClazz = repoConstructor.parameterTypes[0] // 逐层实例化 val dataSource = dsClazz.getDeclaredConstructor().newInstance() val repository = repoConstructor.newInstance(dataSource) vmConstructor.newInstance(repository) as T } catch (e: Exception) { throw IllegalArgumentException("ViewModel实例化失败:${modelClass.simpleName}", e) } } }
注意事项:
- 仅适配构造参数规则完全统一的场景,规则变动时需要同步修改反射逻辑
- 存在少量反射开销,对性能要求极高的场景优先选择方案1
补充优化方案
如果项目已接入Hilt依赖注入框架,直接给ViewModel添加@HiltViewModel注解即可,无需手动实现ViewModelFactory,Hilt会自动生成全局统一的工厂实现,完全消除样板代码。
内容的提问来源于stack exchange,提问作者Kriyan Tech Zone
相关产品推荐
相关产品推荐

