我有一个用这个XML调用setContentView的Activity:
<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。这显示正确,但是当屏幕旋转时,我得到一个强制关闭。
从DialogFragment.show(FragmentManager,String)以外的其他片段中显示DialogFragment的正确方法是什么?
答案 0 :(得分:54)
兼容性库中存在可能导致此问题的错误。试着把它放在对话片段中:
@Override
public void onDestroyView() {
if (getDialog() != null && getRetainInstance())
getDialog().setOnDismissListener(null);
super.onDestroyView();
}
我还建议将您的dialogfragment设置为保留,因此在轮换后不会被解除。把“setRetainInstance(true);”例如在onCreate()方法中。
答案 1 :(得分:11)
好的,虽然Zsombor的方法有效,但这是由于我对Fragments缺乏经验而且他的解决方案导致了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) {
...
}
}
并向他们展示:
private void showMyDialog() {
MyDialogFragment d = MyDialogFragment.newInstance();
d.show(getFragmentManager(), "dialog");
}
这可能是ActionBarSherlock库所独有的,但SDK文档中的官方示例也使用此范例。
答案 2 :(得分:2)
要克服Bundle
始终为空,我将其保存到onSaveInstanceState
中的静态字段。这是代码味道,但我找到了恢复对话框和保存状态的唯一解决方案。
Bundle引用应该在onDestroy
中隐藏。
@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;
}
答案 3 :(得分:1)
我使用了所提出的解决方案的混合,并添加了一件事。 这是我的最终解决方案:
我在onCreateDialog中使用了setRetainInstance(true); 我用过这个:
public void onDestroyView() {
if (getDialog() != null && getRetainInstance())
getDialog().setDismissMessage(null);
super.onDestroyView();
}
作为savedInstanceState无法解决的解决方法,我创建了一个名为StateHolder的私有类(与为listView创建持有者的方式相同):
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。创建对话框时,它会验证stateHolder是否为null以恢复状态或只是正常初始化所有内容。
答案 4 :(得分:1)
我用@ZsomborErdődy-Nagy和@AndyDennie的答案解决了这个问题。您必须将此类以及父级片段调用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();
}
}
答案 5 :(得分:0)
我有一个类似的问题,但上述都没有对我有用。最后,我需要在代码中而不是在XML布局中创建片段。
答案 6 :(得分:0)
我在我的项目中碰到了这个,上述解决方案都没有帮助。
如果异常看起来像
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),这是这种情况的常见建议。
答案 7 :(得分:0)
我遇到了这个问题而且onDestroyView()
伎俩并没有奏效。事实证明,这是因为我在onCreate()
中进行了一些相当密集的对话创建。这包括保存对AlertDialog
的引用,然后我将在onCreateDialog()
中返回。
当我将所有这些代码移到onCreateDialog()
并停止保留对该对话框的引用时,它又开始工作了。我希望我违反了其中一个不变量DialogFragment
关于管理其对话框的内容。
答案 8 :(得分:0)
在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;
}