AndroidRuntimeException:在DialogFragment中添加内容之前必须调用requestFeature()

Fel*_*das 6 android modal-dialog android-fragments

我知道这个问题已经在这里多次询问,但是在花了最后1.5小时阅读并试图解决我的问题后,我不能.

问题陈述:

setStyleDialogFragmenti中调用方法时,会在标题中声明RuntimeException错误.

这是我的原始代码,它不会抛出此异常:

public class MapDialogFragment extends DialogFragment

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.maps_dialog, container, false);
        return view;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我刚刚在我的应用程序中添加了ImmersiveMode.正如你们中的一些人可能知道的那样,沉浸式模式在显示Dialogs时会丢失,因此必须覆盖这些片段并设置适当的标志以保持模式.我成功地完成了这项工作 - 它有效.但是,我必须评论一下:setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);所以我失去了对话框的风格,这就是问题所在.

仔细看看setStyleDialogFragment 中的方法,我无法真正看到如何requestFeature()调用它:

public void setStyle(int style, int theme) {
        mStyle = style;
        if (mStyle == STYLE_NO_FRAME || mStyle == STYLE_NO_INPUT) {
            mTheme = com.android.internal.R.style.Theme_DeviceDefault_Dialog_NoFrame;
        }
        if (theme != 0) {
            mTheme = theme;
        }
    }
Run Code Online (Sandbox Code Playgroud)

最后,这是我的DialogFragment类,其中发生异常.注意getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);以及clearFlag,它们是使ImmersiveMode工作所必需的(希望这对某人有用):

public class MapDialogFragmentv2 extends DialogFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        //I have also tried the code here, before the super.OnCreate but to no avail
        //setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);
        super.onCreate(savedInstanceState);
    }

    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {
        MyDialog mDialog = new MyDialog(getActivity());

        mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

        view = getActivity().getLayoutInflater().inflate(R.layout.maps_dialog, null);

        //Line below throws exception. Needs to be commented out
        setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);
        mDialog.setContentView(view);

        return mDialog;
    }

    public class MyDialog extends Dialog {
        public MyDialog(Context context) {
            super(context);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
            getWindow().getDecorView().setSystemUiVisibility(MainActivity.getImmersiveModeFlags());
        }

        @Override
        public void show() {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
            super.show();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我一直在使用的混合也试过onCreate,onCreateView而且onCreateDialog但没有奏效.我还在Stackoverflow上看到有人评论说同时拥有onCreateView和onCreateDialog并不是一个好主意.

并尝试将样式添加到我的xml布局本身,但也没有工作:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/lib/com.google.android.gms.plus"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/transparent"
    style="@android:style/Theme.Holo.Dialog" >
Run Code Online (Sandbox Code Playgroud)

谢谢

Xav*_*ler 5

问题在于,您将太多不同的东西混合在一起,并且您不尊重每个类的生命周期.

首先,你需要像你一样停止嵌套类.这部分是错误的根源.如果你真的想/有嵌套FragmentDialog则你声明嵌套是很重要的Fragments,Dialogs因为静态的.如果您不将它们声明为静态,则可能导致内存泄漏和类似您的问题.但是你能做的最好的事情就是每个文件只限制一个类,除非你有实际的理由来嵌套它.这还有一个额外的好处,即提高代码的可读性和可维护性.

但是你的错误的主要原因是你完全忽略了生命周期Dialog.几乎所有以下代码都应该在以下的适当生命周期方法中Dialog:

mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

view = getActivity().getLayoutInflater().inflate(R.layout.maps_dialog, null);

//Line below throws exception. Needs to be commented out
setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);
mDialog.setContentView(view);
Run Code Online (Sandbox Code Playgroud)

因此,要修复错误,您需要做3件事:

  1. 像这样声明MapDialogFragmentv2MyDialog静态:

    public class MainActivity extends Activity {
    
        ...
    
        public static class MapDialogFragmentv2 extends Fragment {
    
            ...
    
            public static class MyDialog extends Dialog {
                ...
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

或者甚至更好地将它们一起移动到自己的文件中.

  1. 从移动代码onCreateDialog()MapDialogFragmentv2在正确的生命周期方法MyDialog.它应该看起来像这样:

    public static class MyDialog extends Dialog {
    
        private final LayoutInflater mInflater;
    
        public MyDialog(Context context) {
            super(context);
    
            mInflater = LayoutInflater.from(context);
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
            getWindow().getDecorView().setSystemUiVisibility(MainActivity.getImmersiveModeFlags());
    
            View view = mInflater.inflate(R.layout.maps_dialog, null);
            setContentView(view);
        }
    
        @Override
        public void show() {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
            super.show();
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在通话结束后添加setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);onCreate()您的方法中.MapDialogFragmentv2super.onCreate()

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);
    }
    
    Run Code Online (Sandbox Code Playgroud)

MapDialogFragmentv2应该看起来像这样:

public static class MapDialogFragmentv2 extends DialogFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);
    }

    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {
        return new MyDialog(getActivity());
    }
}
Run Code Online (Sandbox Code Playgroud)

我在运行Android 5.0.1(Lollipop)的Nexus 5上测试了所有内容,但它确实有效.