1

THere a tons of question about android.util.AndroidRuntimeException: requestFeature() must be called before adding content. But none of the proposed solutions worked for me.

I have a custom 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
}

I'm showing it like this
newDialogInstance().show(activity.getFragmentManager(), "tag-dialog-fragment");

And each time I get:

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)

Could someone explain me what is going on here?

Martynas Jurkus
  • 8,758
  • 12
  • 52
  • 99

3 Answers3

3

This is a late answer but maybe that'll help someone, the problem comes from the fact that you are trying to inflate the dialog from both onCreateDialog and onCreateView. To avoid this you can avoid using onCreateView and inflate your layout in onCreateDialog instead.

You would get this:

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

Then just remove onCreateView or use it to do other things like using savedInstanceState as explained in this other answer: https://stackoverflow.com/a/15602648/2206688

You can also review the documentation example: http://developer.android.com/guide/topics/ui/dialogs.html#CustomLayout

Community
  • 1
  • 1
Yoann Hercouet
  • 17,272
  • 4
  • 56
  • 80
  • In addition to your answer: This is another point where the documentation is not clear. At http://developer.android.com/reference/android/app/DialogFragment.html#AlertDialog it says "Instead of (or in addition to) implementing onCreateView(LayoutInflater, ViewGroup, Bundle) to generate the view hierarchy inside of a dialog, you may implement onCreateDialog(Bundle) to create your own custom Dialog object. This is most useful for creating an AlertDialog, [...]" It's ok to use onCreateView and also onCreateDialog at the same time, but only if onCreateDialog returns super.onCreateDialog – Matthias Schippling Nov 04 '15 at 09:24
3

Another late answer and I wrote part of it already as a comment but maybe it's useful for someone else as well.

As Yoann already wrote, the problem is that the View is created twice and, in the case of the dialog, it creates its own window which causes the problem. The official documentation (http://developer.android.com/reference/android/app/DialogFragment.html#AlertDialog) makes it seem that it is possible to overwrite onCreateView and onCreateDialog at the same time and show a custom layout that can be embedded or used AlertDialog-styled:

Instead of (or in addition to) implementing onCreateView(LayoutInflater, ViewGroup, Bundle) to generate the view hierarchy inside of a dialog, you may implement onCreateDialog(Bundle) to create your own custom Dialog object.

This is most useful for creating an AlertDialog, [...]

It is possible to overwrite both methods, just not in combination with the AlertDialog.Builder.

What is working for me so far is this:

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

I'm using isInLayout() to decide whether to call the super method or use the custom implementation.

EDIT: This example uses the support library classes: http://developer.android.com/reference/android/support/v7/app/AlertDialog.Builder.html#setView(int)

Matthias Schippling
  • 2,714
  • 1
  • 16
  • 28
-8

Use like this :

@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;
}
Piyush
  • 23,959
  • 6
  • 36
  • 71
  • This is because Each LayoutInflater is tied to a context (which differs between the Activity and the fragment), and fragments complicate things. Additionally, there are a few things that don't work recursively (e.g. dialog within a dialog). I would guess that the problem lies somewhere between instantiation order and recursion, but it might be easier to just roll with it rather than dig further – Piyush Jan 10 '14 at 10:00
  • Further remember more one thing is that you must choose to override only one of **onCreateView** or **onCreateDialog** in a DialogFragment. Overriding both will result in the exception: "requestFeature() must be called before adding content" – Piyush Jan 10 '14 at 10:02
  • Then why is is allowed to `onCreateView` at all if it will result in error? – Martynas Jurkus Jan 10 '14 at 11:41
  • 11
    what ? this answer makes no sense. the builder created is not even used ! – njzk2 Jan 30 '14 at 19:20
  • I don't know..what the hell happened here?? – Burhanuddin Rashid Feb 28 '17 at 13:25