【问题标题】:Inflating view onCreateView custom DialogFragment results in AndroidRuntimeException膨胀视图 onCreateView 自定义 DialogFragment 导致 AndroidRuntimeException
【发布时间】:2019-01-28 13:11:45
【问题描述】:

有很多关于android.util.AndroidRuntimeException: requestFeature() must be called before adding content 的问题。但没有一个建议的解决方案对我有用。

我有一个自定义DialogFragment

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new AlertDialog.Builder(getActivity()).create();
}

@Override
public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.notification_dialog, null);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    //setting up dialog
}

我是这样展示的
newDialogInstance().show(activity.getFragmentManager(), "tag-dialog-fragment");

每次我得到:

android.util.AndroidRuntimeException: requestFeature() must be called before adding content
            at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:226)
            at com.android.internal.app.AlertController.installContent(AlertController.java:234)
            at android.app.AlertDialog.onCreate(AlertDialog.java:337)
            at android.app.Dialog.dispatchOnCreate(Dialog.java:355)
            at android.app.Dialog.show(Dialog.java:260)
            at android.app.DialogFragment.onStart(DialogFragment.java:490)
            at android.app.Fragment.performStart(Fragment.java:1719)

谁能解释一下这里发生了什么?

【问题讨论】:

    标签: android android-fragments


    【解决方案1】:

    这是一个较晚的答案,但也许这会对某人有所帮助,问题在于您试图从onCreateDialogonCreateView 膨胀对话框。为避免这种情况,您可以避免使用onCreateView,而是在onCreateDialog 中扩充您的布局。

    你会得到这个:

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Get the layout inflater
        LayoutInflater inflater = getActivity().getLayoutInflater();
        View layout = inflater.inflate(R.layout.notification_dialog, null);
    
        /** Add modifications on your layout if needed */
    
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        // Add your custom layout to the builder
        builder.setView(layout);
    
        return builder.create();
    }
    

    然后只需删除 onCreateView 或使用它来执行其他操作,例如使用 savedInstanceState,如其他答案所述:https://stackoverflow.com/a/15602648/2206688

    您还可以查看文档示例: http://developer.android.com/guide/topics/ui/dialogs.html#CustomLayout

    【讨论】:

    • 除了您的回答:这是文档不清楚的另一点。在developer.android.com/reference/android/app/… 它说“不是(或除了)实现 onCreateView(LayoutInflater, ViewGroup, Bundle) 来生成对话框内的视图层次结构,您可以实现 onCreateDialog(Bundle) 来创建自己的自定义对话框对象。这个对于创建 AlertDialog 最有用,[...]" 可以同时使用 onCreateView 和 onCreateDialog,但前提是 onCreateDialog 返回 super.onCreateDialog
    【解决方案2】:

    另一个迟到的答案,我已经写了一部分作为评论,但也许它对其他人也有用。

    正如 Yoann 已经写的那样,问题是视图被创建了两次,在对话框的情况下,它创建了自己的窗口,这会导致问题。官方文档 (http://developer.android.com/reference/android/app/DialogFragment.html#AlertDialog) 似乎可以同时覆盖 onCreateViewonCreateDialog 并显示可以嵌入或使用 AlertDialog 样式的自定义布局:

    而不是(或除了)实施 onCreateView(LayoutInflater, ViewGroup, Bundle) 生成视图 对话框内的层次结构,您可以实现 onCreateDialog(Bundle) 创建您自己的自定义对话框对象。

    这对于创建 AlertDialog 最有用,[...]

    可以覆盖这两种方法,但不能与 AlertDialog.Builder 结合使用。

    到目前为止对我有用的是:

    public class CustomDialogFragment extends DialogFragment {
    
        @NonNull
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            if (isInLayout())
                return super.onCreateDialog(savedInstanceState);
    
            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
                    .setView(R.layout.my_custom_layout)
                    .setTitle(R.string.my_title)
                    .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            // TODO implement
                        }
                    });
    
            return builder.create();
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            if (!isInLayout())
                return super.onCreateView(inflater, container, savedInstanceState);
    
            View v = inflater.inflate(R.layout.my_custom_layout, container);
            return v;
        }
    }
    

    我正在使用isInLayout() 来决定是调用超级方法还是使用自定义实现。

    编辑:此示例使用支持库类:http://developer.android.com/reference/android/support/v7/app/AlertDialog.Builder.html#setView(int)

    【讨论】:

    • .setView(R.layout.my_custom_layout) 仅在 API 21 中可用
    • 原来如此,谢谢指正。我的示例使用支持库。我会将其添加到答案中。
    【解决方案3】:

    这样使用:

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    View view = getActivity().getLayoutInflater().inflate(R.layout.notification_dialog, null);
    builder.setView(view);
    return builder;
    }
    

    【讨论】:

    • 这是因为每个 LayoutInflater 都与一个上下文相关联(在 Activity 和片段之间有所不同),片段使事情变得复杂。此外,有一些东西不能递归地工作(例如对话中的对话)。我猜想问题出在实例化顺序和递归之间,但顺其自然而不是进一步挖掘可能更容易
    • 进一步记住一件事是您必须选择仅覆盖 DialogFragment 中的 onCreateViewonCreateDialog 之一。覆盖两者将导致异常:“在添加内容之前必须调用requestFeature()”
    • 那为什么onCreateView会出错呢?
    • 什么?这个答案没有意义。甚至没有使用创建的构建器!
    • 我不知道..这里到底发生了什么??
    猜你喜欢
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多