片段,对话框片段和屏幕旋转

我有一个活动,用这个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> 

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

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

Solutions Collecting From Web of "片段,对话框片段和屏幕旋转"

兼容性库中有一个可能会导致此问题的错误。 尝试把这个在你dialogfragment:

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

我也build议设置你的dialogfragment保留,所以它不会被解雇后轮换。 把“setRetainInstance(true);” 例如在onCreate()方法中。

好的,当Zsombor的方法起作用时,这是由于我对Fragments没有经验,他的解决scheme导致saveInstanceState Bundle出现问题。

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

所以最后,你必须这样写你的DialogFragments:

 public static class MyDialogFragment extends DialogFragment { static MyDialogFragment newInstance() { MyDialogFragment d = new MyDialogFragment(); return d; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { ... } } 

并向他们展示:

 private void showMyDialog() { MyDialogFragment d = MyDialogFragment.newInstance(); d.show(getFragmentManager(), "dialog"); } 

这可能是ActionBarSherlock库所特有的,但SDK文档中的官方示例也使用这种范例。

为了克服Bundle始终为空,我将它保存到onSaveInstanceState一个静态字段。 这是一个代码异味,但我发现恢复对话框和保存状态的唯一解决scheme。

应该在onDestroyonDestroy Bundle引用。

 @Override public void onCreate(Bundle savedInstanceState) { if (savedInstanceState == null) savedInstanceState = HackishSavedState.savedInstanceState; setRetainInstance(true); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { if (savedInstanceState == null) savedInstanceState = HackishSavedState.savedInstanceState; ... } @Override public void onDestroyView() // necessary for restoring the dialog { if (getDialog() != null && getRetainInstance()) getDialog().setOnDismissListener(null); super.onDestroyView(); } @Override public void onSaveInstanceState(Bundle outState) { ... HackishSavedState.savedInstanceState = outState; super.onSaveInstanceState(outState); } @Override public void onDestroy() { HackishSavedState.savedInstanceState = null; super.onDestroy(); } private static class HackishSavedState { static Bundle savedInstanceState; } 

我使用了所提供的解决scheme的组合,并添加了一件事。 这是我的最终解决scheme:

我在onCreateDialog中使用了setRetainInstance(true) 我用这个:

 public void onDestroyView() { if (getDialog() != null && getRetainInstance()) getDialog().setDismissMessage(null); super.onDestroyView(); } 

作为savedInstanceState不起作用的解决方法,我创build了一个名为StateHolder的私有类(与为listView创build持有者的方法相同):

 private class StateHolder { String name; String quantity; } 

我这样保存状态:

 @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); stateHolder = new StateHolder(); stateHolder.name = actvProductName.getText().toString(); stateHolder.quantity = etProductQuantity.getText().toString(); } 

在onDismiss方法中,我将stateHolder设置回null。 当创build对话框时,它会validationstateHolder是否为null,以恢复状态或正常初始化所有内容。

我用@ZsomborErdődy-Nagy和@AndyDennie的答案解决了这个问题。 你必须setRetainInstance(true)这个类,并在你的父级片段中调用setRetainInstance(true)dialogFragment.show(getFragmentManager(), "Dialog");

  public class AbstractDialogFragment extends DialogFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } @Override public void onDestroyView() { if (getDialog() != null && getRetainInstance()) getDialog().setDismissMessage(null); super.onDestroyView(); } } 

我有一个类似的问题,但是,以上都没有为我工作。 最后,我需要在代码中而不是在XML布局中创build片段。

请参阅: 更换碎片和方向更改

我在我的项目中遇到了这个问题,上面的解决scheme都没有帮助。

如果exception看起来像

 java.lang.RuntimeException: Unable to start activity ComponentInfo{ ... Caused by: java.lang.IllegalStateException: Fragment.... did not create a view. 

这是由于回滚后使用的后备容器Id问题导致的。 看到这张票更多细节:

https://code.google.com/p/android/issues/detail?id=18529

基本上你可以通过确保所有的xml片段在布局中定义一个标签来防止崩溃。 这可以防止在可见片段旋转时发生回退情况。

在我的情况下,我能够应用此修补程序, 不必重写onDestroyView()或setRetainInstance(true),这是这种情况的常见build议。

我遇到了这个问题,并onDestroyView()技巧不工作。 事实certificate,这是因为我正在onCreate()做一些相当密集的对话框创build。 这包括保存对AlertDialog的引用,然后我将返回onCreateDialog()

当我将所有这些代码移动到onCreateDialog()并停止保留对该对话框的引用时,它再次开始工作。 我希望我违反了DialogFragment关于pipe理对话框的一个不variables。

onCreate()调用setRetainInstance(true) ,然后包含这个:

 @Override public void onDestroyView() { if (getDialog() != null && getRetainInstance()) { getDialog().setOnDismissMessage(null); } super.onDestroyView(); } 

当您在onCreate()中调用setRetainInstance(true)时,onCreate()将不再在方向更改中调用,但onCreateView()仍将被调用。

所以你仍然可以将状态保存到onSaveInstanceState()包中,然后在onCreateView()检索它:

 @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("myInt", myInt); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_layout, container); if (savedInstanceState != null) { myInt = savedInstanceState.getInt("myInt"); } ... return view; }