[英]Fragments, DialogFragment, and Screen Rotation
我有一個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>
GroupFragment擴展了Fragment,一切都很好。 但是,我在GroupFragment中顯示了一個DialogFragment。 這顯示正確,但是當屏幕旋轉時,我得到一個強制關閉。
從DialogFragment.show(FragmentManager,String)以外的其他片段中顯示DialogFragment的正確方法是什么?
兼容性庫中存在可能導致此問題的錯誤。 試着把它放在你的dialogfragment中:
@Override
public void onDestroyView() {
if (getDialog() != null && getRetainInstance())
getDialog().setOnDismissListener(null);
super.onDestroyView();
}
我還建議將您的dialogfragment設置為保留,因此在輪換后不會被解除。 把“setRetainInstance(true);” 例如在onCreate()方法中。
好的,雖然Zsombor的方法有效,但這是由於我對Fragments缺乏經驗而且他的解決方案導致了saveInstanceState Bundle
問題。
顯然(至少對於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
始終為null,我將其保存到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;
}
我使用了所提出的解決方案的混合,並添加了一件事。 這是我的最終解決方案:
我在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以恢復狀態或僅正常初始化所有內容。
我用@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();
}
}
我在我的項目中碰到了這個,上面的解決方案都沒有幫助。
如果異常看起來像
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),這是這種情況的常見建議。
我遇到了這個問題,並且onDestroyView()
技巧無效。 事實證明,這是因為我在onCreate()
進行了一些相當密集的對話創建。 這包括保存對AlertDialog
的引用,然后我將在onCreateDialog()
返回。
當我將所有這些代碼移動到onCreateDialog()
並停止保留對該對話框的引用時,它再次開始工作。 我希望我違反了一個不變量DialogFragment
關於管理它的對話框。
在onCreate()
調用setRetainInstance(true)
然后包含:
@Override
public void onDestroyView() {
if (getDialog() != null && getRetainInstance()) {
getDialog().setOnDismissMessage(null);
}
super.onDestroyView();
}
當你在onCreate()中調用setRetainInstance(true)
時,onCreate()將不再在方向更改時調用,但仍會調用onCreateView()。
因此,您仍然可以在onSaveInstanceState()
中將狀態保存到bundle中,然后在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;
}
我有一個類似的問題,但上面沒有一個對我有用。 最后,我需要在代碼中而不是在XML布局中創建片段。
請參閱: 更換碎片和方向更改
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.