setRetainInstance(真);做错了?

时间:2013-06-10 20:15:32

标签: android xml

我认为我的应用中发生的事情的例子最适合这个问题。

用户登录后,会将其带到MainActivity。这包含带有标签的ActionBar,默认选择一个标签,用户看到....

    container1              container2

CompanyName: <EditText> |               |
ProjectName: <EditText> |     Welcome   |
   <SearchButton>       |               |

当用户填写这些表单并点击搜索按钮时,他们会看到...

  container1             container2

   <ListView>       |                  |
   BasicInfo        |     Welcome      |
   Assessment       |                  |
   Signature        |                  |

当用户点击“评估”时,他们会看到

   container1             container2

   <ListView>       |     Question#1   |
   BasicInfo        |     Question#2   |
   Assessment       |     Question#3   |
   Signature        |     Question#4   |

现在,当评估fragment膨胀时,它会执行AsyncTask,并为来自Views的问题创建JSON。现在,当用户在此屏幕上时,我不希望屏幕方向更改以再次执行网络请求和AsyncTask。所以我将setRetainInstance(true);放在评估Fragment中,就像这样

public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        view = inflater.inflate(R.layout.fragment_assessment, container, false);
        ab = getActivity().getActionBar();
        infoList = new ArrayList<HashMap<String, String>>();
        allRadio = new ArrayList<RadioGroup>();
        allImageButton = new ArrayList<ImageButton>();
        allSpinner = new ArrayList<Spinner>();
        allEdit = new ArrayList<EditText>();
        allCheck = new ArrayList<CheckBox>();

        new Load().execute();
        setRetainInstance(true);
        return view;
    }

然而,当我在评估Fragment中翻转我的屏幕时,它不仅不会保存布局,而且会将我返回到看起来像这样的父Activity

    container1              container2

CompanyName: <EditText> |               |
ProjectName: <EditText> |     Welcome   |
   <SearchButton>       |               |

不确定我做错了什么。可能是fragment中的XML名称不正确,或者容器名称不正确。这里有代码。

容器XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/MainLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false"
    android:orientation="horizontal" >

    <LinearLayout
        android:id="@+id/header_fragment_container"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1.2"
        android:background="@drawable/green_gradient"
        android:orientation="vertical" >
    </LinearLayout>

    <LinearLayout
        android:id="@+id/content_fragment_container"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:background="@drawable/twoglobe_line"
        android:orientation="vertical"
        android:scrollbars="vertical" >
    </LinearLayout>

</LinearLayout>

评估片段XML

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/basic_info_scroll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/twoglobe_line"
    android:gravity="center"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/gen_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="10dp"
        android:gravity="center"
        android:orientation="vertical" >

        <LinearLayout
            android:id="@+id/add"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:layout_marginTop="10dp"
            android:orientation="vertical" >
        </LinearLayout>
    </LinearLayout>

</ScrollView>

所以我期待来自setRetainInstance(true);行的不切实际的结果,或者我只是做错了?任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:2)

我不知道这是否正确,但这就是我这样做的方式,对我有用。

在我的布局中,我没有片段本身,我只有容器可以容纳它们。然后,在我的应用程序开始时,我看到我的任何片段是否已经加载(它们将在平板电脑布局中),如果不是,我会查看savedState包中是否有任何内容。如果该Bundle为null,那么我知道我的应用程序刚刚第一次启动,我可以加载我的“home”片段。否则我在onSaveInstanceState()中放了一个密钥让我知道要加载哪个片段。所以我将让FragmentManager将其中一个加载到容器中。

答案 1 :(得分:1)

对于第一个屏幕,我会使用单独的活动。 CaseyB的答案非常好,实际上我也是这样做的(现在,当你有很多方向改变,而且背板上的一些东西,你会得到强制关闭,但它不可避免)。我要做的是第一个屏幕,使它成为自己的活动,然后调用第二个FragmentActivity并使左侧的片段静态(意味着用XML定义)。那样你就不用担心了。然后,您可以专注于正确的片段。如果设置setRetainInstance,则无需担心重新创建视图。但是,如果它进入后台,那么你将失去一切。它从不调用onDestroy,只调用onDetach。而onCreate只在第一次创建片段时调用。所以,我会避免使用onCreate,并专注于使用onActivityCreated()和onAttach()来实例化值和诸如此类

更新 - 使用onCreate()方法设置setRetainInstance(true)并调用JSON和网络代码来创建视图。在这里做它很重要,所以它只被调用一次。 这应该完全适用于方向更改和在片段之间来回切换(后端堆栈可以工作,只是你不能在backstack中将它设置为retainInstance。这是我的错字)。

然后,当片段重新启动时,你想要调用的任何其他代码,使用onAttach(),因为onCreate()不会被调用,因为它从未被破坏

然后,为了再次控制你的项目,你不能使用getActivity()。findViewById(),你必须使用this.getView()。findViewById()。我不知道为什么会这样(因为你会认为它将附加到活动视图组,但它不是)。这应该是你应该打的唯一打嗝。除此之外,它应该完美无缺。

答案 2 :(得分:1)

我实际上还没有弄清楚如何正确使用这个setRetainInstance()方法。我不得不暂时使用

android:configChanges="orientation|keyboardHidden|screenSize

在我的清单中。我从多个人那里听说,这是不鼓励的,并且错误的方式来做到这一点。所以这个主题仍然是开放的,我将接受任何正确说明我应该如何正确使用此代码的答案。