DialogFragment中调用getViewLifecycleOwner()崩溃,能否正常使用该方法?
当然可以在DialogFragment中使用getViewLifecycleOwner(),但你遇到的错误是因为时机不对——咱们得先搞清楚DialogFragment的生命周期顺序问题。
你看到的
IllegalStateException,本质是因为在onCreateDialog()方法执行时,DialogFragment的View还没被创建(onCreateView()还没执行),这时候getView()返回null,而getViewLifecycleOwner()依赖于已存在的View,直接调用就会触发报错。
下面分两种常见场景给你解决方案:
场景1:你的DialogFragment使用自定义View(重写了onCreateView)
如果你的弹窗是通过onCreateView()加载自定义布局实现的,最稳妥的做法是把LiveData的观察逻辑移到onViewCreated()方法里——这个方法会在View创建完成后执行,此时调用getViewLifecycleOwner()完全安全:
class MyCustomDialog : DialogFragment() { private val viewModel: MyViewModel by viewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.my_dialog_layout, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 这里可以放心使用getViewLifecycleOwner() viewModel.myLiveData.observe(getViewLifecycleOwner()) { data -> view.findViewById<TextView>(R.id.tv_content).text = data.toString() } } // 如果需要自定义Dialog样式,可重写onCreateDialog,但不要在这里处理LiveData观察 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = super.onCreateDialog(savedInstanceState) dialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) return dialog } }
场景2:你直接在onCreateDialog()里构建AlertDialog
如果你的弹窗完全通过AlertDialog.Builder在onCreateDialog()里构建,不想依赖onCreateView(),可以用Fragment提供的viewLifecycleOwnerLiveData——它会在View创建完成后自动返回有效的LifecycleOwner:
class MyAlertDialog : DialogFragment() { private val viewModel: MyViewModel by viewModels() override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = AlertDialog.Builder(requireContext()) .setTitle("提示") .setView(R.layout.dialog_content) .setPositiveButton("确认", null) .create() // 监听View生命周期Owner的就绪状态 viewLifecycleOwnerLiveData.observe(this) { lifecycleOwner -> viewModel.myLiveData.observe(lifecycleOwner) { data -> // 注意判空,避免Dialog未完全初始化时findViewById返回null dialog.findViewById<TextView>(R.id.tv_message)?.text = data } } return dialog } }
额外提醒:别乱用getLifecycleOwner()
有些开发者会图省事直接用getLifecycleOwner()代替,但两者有本质区别:
getLifecycleOwner()绑定的是DialogFragment本身的生命周期(从onCreate()到onDestroy())getViewLifecycleOwner()绑定的是DialogFragment中View的生命周期(从onCreateView()到onDestroyView())
如果用getLifecycleOwner(),当屏幕旋转导致View销毁重建时,Fragment本身还活着,LiveData的观察者不会自动解绑,可能导致内存泄漏或者重复回调。所以除非你明确需要在Fragment整个生命周期都观察,否则优先用getViewLifecycleOwner()相关的方案。
内容的提问来源于stack exchange,提问作者Alex.Marynovskyi

