AndroidRuntimeException:requestFeature() must be called before adding content in DialogFragment

文章标签: android,android-fragments
2015-1-6 9:17:12     人阅读    

AndroidRuntimeException:requestFeature() must be called before adding content in DialogFragment


这个问题应该被提问过好多次,我花费了5个小时从晚上找问题解决办法都是最后还是没有解决.
问题情况如下:
When calling setStyle method in DialogFragment i get the RuntimeException error stated in the title.
在DialogFragment 中 调用setStyle,在title中报错   RuntimeException error ,
下面是我的源代码,没有任何异常

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

 

现在,我在我的应用程序添加Immersive Mode。正如一些人可能都知道,在显示对话框的时候 Immersive 模式失效了,为了保证Immersive 模式有效,必须要覆盖这些fragments ,并设置恰当的标识 。

当然,我也成功的做到这一点,但是现在我需要注释掉   setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);,  这行代码,注释掉之Immersive 模式又丢失了
有仔细看看在DialogFragment中的SetStyle方法,我看不到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;
        }
    }

下面的  MapDialogFragmentv2 类就是发生异常的类,需要注意的是 
 the getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); 和  clearFlag 都是 Immersive Mode 工作正常需要的代码

 

public class MapDialogFragmentv2 extends DialogFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        //  我在这里试验过,在super.OnCreate  之前调用,但是失败了 
        //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);

        //下面的代码报异常
        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();
        }
    }
}

 

<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" >

 

处理方法

问题的原因是你把太多不同的东西混搭在一期,没有理解类的生命周期
首先,你需要停止嵌套类,这部分是错误的来源。如果你真需要/必须嵌套对话框和Fragment,你需要把他们声明成静态类,如果你不声明为静态的,你可能会导致内存泄漏。

你最大的问题时没有正确的使用Dialog 的生命周期  ,匹配下面的代码就能解决你的问题

mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
view = getActivity().getLayoutInflater().inflate(R.layout.maps_dialog, null);

//下面的代码报异常了,
setStyle(DialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Holo);
mDialog.setContentView(view);


你需要做如下3个步骤来解决这个问题

 按照如下的静态声明 MapDialogFragmentv2 和  MyDialog 

   public class MainActivity extends Activity {

    ...

    public static class MapDialogFragmentv2 extends Fragment {

        ...

        public static class MyDialog extends Dialog {
            ...
        }
    }
}

 

把代码从 MapDialogFragmentv2 的onCreateDialog() 移动到  正确的生命周期方法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();
    }
}

     


在MapDialogFragmentv2 类  onCreate()方法中 super.onCreate() 的后面调用setStyle

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

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


最后你的 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());
    }
}


我在   Nexus 5 running Android 5.0.1 (Lollipop)测试通过


原文地址:http://www.itmmd.com/201501/445.html
该文章由 萌萌的IT人 整理发布,转载须标明出处。

android学习笔记(35)android AlertDialog创建列表对话框[2]   上一篇
下一篇  android shareSDK sso登录新浪和微信
精彩回复
我要追加问题,请求站长解决!
姓名:       

《程序员app》专门为程序员量身定做!