簡體   English   中英

片段,DialogFragment和屏幕旋轉

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM