我使用DialogFragment (onCreateDialog)
和ViewModel。但是,当我尝试使用getViewLifecycleOwner()传递observe()方法时,出现如下错误:
java.lang.IllegalStateException: Can't access the Fragment View's LifecycleOwner when getView() is null i.e., before onCreateView() or after onDestroyView().
是否可以在DialogFragment中使用getViewLifecycleOwner()?
答案 0 :(得分:7)
发生这种情况的原因是如何创建DialogFragment。
如果您使用onCreateDialog()
,则此类型的Fragment使用略有不同的生命周期。 onCreateView()
将不会被使用,因此此Fragment的viewLifecycleOwner
将不会初始化。
为此,您可以使用Fragment实例作为观察者的所有者:
.observe(this, Observer {...}
。尽管您会收到使用this
而不是viewLifecycleOwner
的警告。
答案 1 :(得分:2)
发生这种情况是因为DialogFragment
的生命周期不同于Fragment
; onCreateDialog
在onCreateView
之前被调用,因此viewLifecycleOwner
不可用...我通过以下方法解决了该问题:
onCreateView
而非onCreateDialog
viewLifecycleOwner
内访问onCreateView
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>
答案 2 :(得分:1)
This is the official recommendation 用于 DialogFragment
:
注意:在订阅生命周期感知组件(例如 LiveData
)时,切勿将 viewLifecycleOwner
用作 LifecycleOwner
中的 DialogFragment
使用 Dialogs
。相反,请使用 DialogFragment
本身,或者如果您使用的是 Jetpack Navigation,请使用 NavBackStackEntry
。
所以你可以像往常一样观察事情,但你传递的不是 viewLifecycleOwner
,而是 this
,或者当前的 backstack 条目(例如 findNavController().currentBackStackEntry
)。无需覆盖 onCreateView
只是为了强制创建 viewLifecycleOwner
或任何东西!
答案 3 :(得分:0)
是否可以在DialogFragment中使用getViewLifecycleOwner()?
是
请尝试将您的逻辑放入matdialog.open(OrderComponent, { data: {editId: "youruniqueid" } });
中,因为那时候您的视图将不会为null,这会导致该异常。
您还可以使用onActivityCreated()
并通过在其上附加可观察对象,可以将逻辑放入该可观察对象中,该逻辑将在初始化getViewLifecycleOwnerLiveData()
后立即开始。
答案 4 :(得分:0)
此错误有可能是您第一次从Repository / ViewModel返回空的LiveData实例。确保您是否已在Repository / ViewModel中启动LiveData。
答案 5 :(得分:0)
您的情况略有不同,但我认为概念是相同的。只需在对话框类中使用 this.getActivity()
并将其作为 LifeCycleOwner
传递即可。我遇到了同样的问题,因为我使用了 LiveData
和 Retrofit
并且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;
}
答案 6 :(得分:0)
我的解决方案有点古怪...
我的组件正在使用getViewLifecycleOwnerLiveData()....所以:
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);
}
因为FragmentViewLifecycleOwner是包私有的...这就是MyLifeCycleOwner类的原因。
由于Android架构管理不善,我不会更改组件。
答案 7 :(得分:0)
因为 DialogFragment
弹出父片段的视图,所以它可以使用其生命周期所有者。因此代码将如下所示:
parentFragment?.viewLifecycleOwner?.let {
binding.lifecycleOwner = it
}