如何为自定义DialogFragment设置泛型<T: ViewModel>作为构造入参
实现方案
你需要的泛型化传入任意ViewModel的CustomDialogFragment有两种实现方式,分别适配不同的使用场景:
方案1:构造直接传入ViewModel(仅适用于无需处理配置变更重建的场景)
如果你的App禁用了横竖屏切换,不需要考虑DialogFragment被系统重建的场景,可以直接按预期写法实现:
定义Dialog代码
import androidx.lifecycle.ViewModel import androidx.fragment.app.DialogFragment class CustomDialog<T : ViewModel>(private val viewModel: T) : DialogFragment() { // 此处编写Dialog的业务逻辑,直接调用viewModel即可,类型为传入的泛型T }
调用代码
// 传入ViewModelA实例 val mDialog1: CustomDialog<ViewModelA> by lazy { CustomDialog(viewModel as ViewModelA) } // 传入ViewModelB实例 val mDialog2: CustomDialog<ViewModelB> by lazy { CustomDialog(viewModel2 as ViewModelB) }
注意:该方案存在缺陷,当触发配置变更(横竖屏切换、系统语言更改等)导致Dialog被系统销毁重建时,系统会调用无参构造方法,传入的ViewModel实例会丢失,可能引发崩溃。
方案2:官方规范实现(推荐,支持配置变更)
该方案不需要直接传入ViewModel实例,由Dialog内部从宿主(父Fragment/Activity)的作用域自动获取对应类型的ViewModel,完全符合Android开发规范:
定义Dialog代码
import androidx.fragment.app.viewModels import androidx.lifecycle.ViewModel import androidx.fragment.app.DialogFragment class CustomDialog<T : ViewModel>(private val viewModelClass: Class<T>) : DialogFragment() { // 和宿主共用同一个ViewModel实例,生命周期和宿主绑定 val viewModel: T by viewModels( // 若需要和Activity共用ViewModel,将ownerProducer改为{ requireActivity() } ownerProducer = { requireParentFragment() } ) companion object { fun <T : ViewModel> create(viewModelClass: Class<T>): CustomDialog<T> { return CustomDialog(viewModelClass) } } // 此处编写Dialog的业务逻辑,直接调用viewModel即可 } // Kotlin 简化调用的扩展方法(可选) inline fun <reified T : ViewModel> createCustomDialog(): CustomDialog<T> { return CustomDialog.create(T::class.java) }
调用代码
// 创建持有ViewModelA的Dialog val mDialog1 by lazy { createCustomDialog<ViewModelA>() } // 创建持有ViewModelB的Dialog val mDialog2 by lazy { createCustomDialog<ViewModelB>() }
内容的提问来源于stack exchange,提问作者Zainab Zafar
相关产品推荐
相关产品推荐

