Android DialogFragment中的getViewLifecycleOwner()导致崩溃

Android DialogFragment中的getViewLifecycleOwner()导致崩溃,android,viewmodel,dialogfragment,android-livedata,Android,Viewmodel,Dialogfragment,Android Livedata,我使用了DialogFragment(onCreateDialog)和ViewModel。但是,当我尝试将getViewLifecycleOwner()传递给LiveData::observe方法时,我得到以下错误: java.lang.IllegalStateException:当getView()为null时,即onCreateView()之前或onDestroyView()之后,无法访问片段视图的LifecycleOwner。 是否可以在对话框片段中使用getViewLifecycleO

我使用了
DialogFragment(onCreateDialog)
和ViewModel。但是,当我尝试将
getViewLifecycleOwner()
传递给
LiveData::observe
方法时,我得到以下错误:

java.lang.IllegalStateException:当getView()为null时,即onCreateView()之前或onDestroyView()之后,无法访问片段视图的LifecycleOwner。

是否可以在
对话框片段中使用
getViewLifecycleOwner()

您的案例略有不同,但我认为概念是相同的。只需在对话框类中使用
this.getActivity()
,并将其作为
LifeCycleOwner
传递即可。我也有同样的问题,因为我使用了
LiveData
reformation
并且
LiveData
需要一个参考。
DialogFragment
在某个点设置其
LifeCycleOwner
,但它不在上述任何方法中。通过使用
getActivity()
,您可以早在onCreateDialog方法中使用观察者。下面是我的代码的某些部分,当我试图传递一个引用为null的
this.getViewLifecycleOwner()
而不是活动时,它首先导致了一些问题

@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
       FragmentActivity activity = this.getActivity();
       binding = DialogSelectIssuesBinding.inflate(LayoutInflater.from(getContext()));

       RetroRepository.
            getDefault().
            getAllIssues().
            observe(this.getActivity(), listLiveDataResponse -> {
                //ToDo Check for errors and Bind the data here 
            });


       AlertDialog alertDialog = new AlertDialog.Builder(activity)
                            .setView(binding.getRoot())
                            .setTitle("Please select issues from the list below:")
                            .setNegativeButton("CANCEL", null)
                            .setPositiveButton("ADD", null)
                            .create();
       alertDialog.setCanceledOnTouchOutside(false);
       return alertDialog;
}

这是因为DialogFragment是如何创建的。 如果使用
onCreateDialog()
,则此类型的片段将使用稍微不同的生命周期。不会使用
onCreateView()
,因此不会初始化此片段的
viewLifecycleOwner

作为解决方法,您可以使用片段实例作为观察者的所有者:
。观察(这个,观察者{…}
。虽然使用
this
而不是
viewLifecycleOwner
会收到警告,但发生这种情况是因为
DialogFragment
的生命周期与
Fragment
不同;
onCreateDialog
onCreateView
之前被调用,因此
viewLifecycleOwner
不可用le…我通过以下方式解决了这个问题:

  • 实现
    onCreateView
    而不是
    onCreateDialog
    • 可以从
      onCreateView中访问
      viewLifecycleOwner
    • onCreateView
      返回的视图由
      DialogFragment
      为我们放入一个对话框中
    • 您需要在对话框中创建自己的按钮和标题
补充守则:

class TextInputDialogFragment : DialogFragment() {

    ...

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        val viewBinding = FragmentDialogTextInputBinding.inflate(layoutInflater, container, false)

        val titleText = params.title.localize(requireContext())
        viewBinding.toolbar.isVisible = titleText.isNotBlank()
        if (titleText.isNotBlank()) {
            viewBinding.toolbar.title = titleText
        }

        viewBinding.recyclerview.adapter = ListItemAdapter(
            viewLifecycleOwner, requireContext().app.nowFactory, viewModel.fields
        )

        viewBinding.buttonAffirm.setOnClickListener {
            listener.onOkPressed(viewModel.userInputtedText.value)
            dismiss()
        }

        viewBinding.buttonReject.setOnClickListener {
            dismiss()
        }

        viewModel.enablePositiveButton.observe(viewLifecycleOwner) { isEnabled ->
            viewBinding.buttonAffirm.isEnabled = isEnabled
        }

        return viewBinding.root
    }

    ...
}
使用的布局文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="?attr/actionBarSize"
            tools:title="Title" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

        <LinearLayout
            style="?buttonBarStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clickable="false"
            android:gravity="end"
            android:orientation="horizontal"
            android:padding="@dimen/min_touch_target_spacing_half">

            <Button
                android:id="@+id/button_reject"
                style="?buttonBarButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/min_touch_target_spacing_half"
                android:text="@android:string/cancel" />

            <Button
                android:id="@+id/button_affirm"
                style="?buttonBarButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/min_touch_target_spacing_half"
                android:text="@android:string/ok" />

        </LinearLayout>

    </LinearLayout>

</layout>

我的解决方案有点古怪

我的组件使用getViewLifecycleOwnerLiveData()…因此:

private final MyLifeCycleOwner owner=new MyLifeCycleOwner();
私有最终MutableLiveData结果=新的MutableLiveData();
@非空
@凌驾
public LiveData getViewLifecycleOwnerLiveData(){
返回结果;
}
@凌驾
公共无效onDestroyView(){
super.onDestroyView();
owner.HandleLifeCycleeEvent(Lifecycle.Event.ON_DESTROY);
result.setValue(null);
}
@可空
@凌驾
创建视图时的公共视图(@NonNull LayoutInflater inflater、@Nullable ViewGroup container、@Nullable Bundle savedInstanceState){
结果。设置值(所有者);
owner.getLifecycle();
owner.handleLifeCycleeEvent(Lifecycle.Event.ON_CREATE);
返回super.onCreateView(充气机、容器、savedInstanceState);
}
因为FragmentViewLifecycleOwner是包私有的…这就是MyLifeCycleOwner类的原因


由于android架构管理不善,我不打算更改我的组件…

onCreateDialog
中,对话框正在创建,但尚未创建。请尝试
onViewCreated()
。我自己没有太多使用
LifecycleOwner
DialogFragment
中未调用创建的视图
,使用
this
(MyDialogFragment)我似乎没有收到任何警告。这种方法比使用
getActivity()
Requiresponsibility()更可取吗
?@ban geoengineering,只要您不使用同一个片段实例多次显示对话框片段。如果您这样做,观察员将在第二次订阅,并且由于重复观察,您可能会遇到奇怪的问题。这是因为使用
this
作为生命周期所有者,只有在<调用code>onDestroy
,而不是通过简单地关闭对话框来调用它。如果片段被销毁,然后重新创建,但活动没有被销毁,该怎么办?旧的观察者仍然引用旧的片段,并且您自己也有内存泄漏。
viewLifecycleOwner
的全部要点是在片段被销毁时删除观察者。
private final MyLifeCycleOwner owner = new MyLifeCycleOwner();

private final MutableLiveData<LifecycleOwner> result = new MutableLiveData<>();

@NonNull
@Override
public LiveData<LifecycleOwner> getViewLifecycleOwnerLiveData() {
    return result;
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    owner.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
    result.setValue(null);
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    result.setValue(owner);
    owner.getLifecycle();
    owner.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    return super.onCreateView(inflater, container, savedInstanceState);
}