片段,DialogFragment和屏幕旋转

Wes*_*ton 25 android android-fragments

我有一个Activity,用这个XML调用setContentView:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal"
    >
    <fragment android:name="org.vt.indiatab.GroupFragment"
        android:id="@+id/home_groups"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1" />
            <..some other fragments ...>
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

GroupFragment扩展了Fragment,一切都很好.但是,我在GroupFragment中显示了一个DialogFragment.这显示正确,但是当屏幕旋转时,我得到一个强制关闭.

从DialogFragment.show(FragmentManager,String)以外的其他片段中显示DialogFragment的正确方法是什么?

Zso*_*agy 54

兼容性库中存在可能导致此问题的错误.试着把它放在你的dialogfragment中:

@Override
public void onDestroyView() {
  if (getDialog() != null && getRetainInstance())
    getDialog().setOnDismissListener(null);
  super.onDestroyView();
}
Run Code Online (Sandbox Code Playgroud)

我还建议将您的dialogfragment设置为保留,因此在轮换后不会被解除.把"setRetainInstance(true);" 例如在onCreate()方法中.

  • 请注意,有报告称`getDialog().setOnDismissListener(null);`会导致某些设备崩溃.解决方法是调用`getDialog().setDismissMessage(null);`代替.有关详细信息,请参阅[此问题](http://code.google.com/p/android/issues/detail?id=17423). (22认同)
  • setRetainInstance(true)修复了崩溃,但对话框只是在方向更改时被解除.同时具有setRetainInstance(true)和上面的代码片段将导致重新显示它.唯一的问题是,以某种方式,savedInstanceState Bundle被搞砸了.在方向改变后我无法恢复我的价值观.调用onCreateDialog()时,Bundle始终为null.有任何想法吗? (10认同)
  • 是的,这会导致我的`IllegalStateException`:`OnDismissListener已被DialogFragment占用,无法替换.但``setDismissMessage`效果很好. (3认同)

Wes*_*ton 11

好吧,虽然Zsombor的方法有效,但这是由于我对片段缺乏经验而且他的解决方案导致了问题saveInstanceState Bundle.

显然(至少对于DialogFragment),它应该是一个public static class.你也必须编写自己的static DialogFragment newInstance()方法.这是因为Fragment类newInstance在其instantiate()方法中调用该方法.

总而言之,你必须像这样编写DialogFragments:

public static class MyDialogFragment extends DialogFragment {

    static MyDialogFragment newInstance() {
        MyDialogFragment d = new MyDialogFragment();
        return d;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

并向他们展示:

private void showMyDialog() {
    MyDialogFragment d = MyDialogFragment.newInstance();
    d.show(getFragmentManager(), "dialog");
}
Run Code Online (Sandbox Code Playgroud)

这可能是ActionBarSherlock库所独有的,但SDK文档中的官方示例也使用此范例.

  • 您不必编写"您自己的"newInstance()方法,因为Fragment.instantiate()正在调用[Class.newInstance()](http://developer.android.com/reference/java/lang/Class.html #的newInstance%28%29).但是因为您的片段实例可能使用Class.newInstance()进行实例化,所以您必须为您编写的每个片段提供显式的默认构造函数. (15认同)
  • 我同意@Szabolcs Berecz,DialogFragment不需要静态构造函数,但它需要一个公共的空(无参数)构造函数,因此可以通过Class.newInstance()方法正确初始化它. (2认同)