设备旋转后恢复数据的问题

Issue with restoring data after device was rotated

我查了很多和我类似问题的其他答案,但还是不明白那里出了什么问题。

我有activity和片段

main_activity.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:id="@+id/fragment_container"
        android:background="#CCC"/>

</LinearLayout>

MainActivity.java

public class MainActivity extends Activity {

    private LinearLayout fragmentContainer;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("LOG", "onCreate");
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null) {
            openFragment();
        } else {
            replaceFragment();
        }
    }

    private void openFragment() {
        final LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.HORIZONTAL);
        ll.setId(12345);
        getFragmentManager().beginTransaction().add(ll.getId(),
            new SimpleFragment(), "SimpleFragment").commit();

        fragmentContainer = (LinearLayout) findViewById(R.id.fragment_container);
        fragmentContainer.addView(ll);
    }

    private void replaceFragment() {
        final LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.HORIZONTAL);
        ll.setId(12345);
        getFragmentManager().beginTransaction().replace(ll.getId(),
            new SimpleFragment(), "SimpleFragment").commit();

        fragmentContainer = (LinearLayout) findViewById(R.id.fragment_container);
        fragmentContainer.addView(ll);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("LOG", "onDestroy");
    }
}

和简单片段

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Simple Fragment"/>

</LinearLayout>
public class SimpleFragment extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);       
        if (savedInstanceState != null) {
            String aaa = savedInstanceState.getString("AAA");
            Toast.makeText(getActivity(), aaa, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(getActivity(), "NULL", Toast.LENGTH_SHORT).show();
        }
        Log.d("LOG", "onCreate");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d("LOG", "fragment onCreateView");
        return inflater.inflate(R.layout.simple_fragment, null);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d("LOG", "fragment onDestroyView");
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("AAA", "Hello");
    }

}

那么问题是什么:

当我旋转设备时,应用程序应该保存一个状态然后恢复它(让我们假设一些变量)。

旋转后立即执行 onSaveInstanceState。 数据已保存。 然后执行fragment的onCreate,恢复数据

没关系。这是预期的行为。

但由于 activity 也被重新创建,片段应该再次添加(替换)。结果片段的 onCreate 再次执行。我看到没有保存数据的片段。我看到新创建的片段。

如何避免这种创建?

我旋转设备,数据被保存然后恢复。片段在 activity 上可见且数据已恢复。

那么在activity中添加片段的算法是什么,以便在旋转后不添加片段并避免重新创建?

从布局添加

一般来说,您不需要从代码中为您的片段添加额外的容器。添加片段的最简单方法是在布局中使用 android:id 属性!!!

定义 <fragment .../>

您的案例示例:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("LOG", "onCreate");
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("LOG", "onDestroy");
    }
}

main_activity.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
    >

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#CCC"
        android:orientation="vertical"
        >

        <fragment
            android:id="@+id/fragment"
            android:name="your.package.name.SimpleFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
    </FrameLayout>

</LinearLayout>

片段代码和布局不需要任何更改。

从代码添加

如果您确实需要从代码中添加它,则不需要从代码中添加额外的容器。如果是首次启动,只需添加片段 - 系统会为您完成后。

您的案例示例:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("LOG", "onCreate");
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null) {
            openFragment();
        }
    }

    private void openFragment() {
        getFragmentManager().beginTransaction().add(R.id.fragment_container,
                new SimpleFragment(), "SimpleFragment").commit();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("LOG", "onDestroy");
    }
}

main_activity.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:id="@+id/fragment_container"
        android:background="#CCC"/>

</LinearLayout>

片段代码和布局不需要任何更改。