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);
}