如何在 orientation/configuration 更改后保持 ListView 片段状态?

How to maintain ListView fragment state after orientation/configuration change?

我的应用程序中有一个 ListView 片段遇到了一些问题。

  1. 当我滚动到列表视图中的特定元素,然后旋转设备时,列表视图重置到列表顶部。
  2. 当我在列表视图中进入多 select 模式,然后旋转设备时,selected 列表项重置。

这是我的 activity:

public class TestActivity extends ActionBarActivity
{
    protected static final String   FRAGMENT_TAG    = "TEST";

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);

        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FragmentManager fm = getFragmentManager();
        TestFragment f = (TestFragment)fm.findFragmentByTag(FRAGMENT_TAG);

        // If no fragment exists, then create a new one and add it!
        if (f == null)
        {
            fm.beginTransaction().add(R.id.fragment_holder, new TestFragment(), FRAGMENT_TAG)
                    .commit();
        }
    }
}

这里是main_layout.xml:

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

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize" >
    </android.support.v7.widget.Toolbar>

    <FrameLayout
        android:id="@+id/fragment_holder"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

这是我的 TestFragment class,还有杂项。删除的内容:

public class TestFragment extends ListFragment
{
    @Override
    public void onActivityCreated(Bundle savedInstanceState)
    {
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState)
    {
        super.onViewCreated(view, savedInstanceState);

        // Sets the list up for multiple choice selection.
        ListView listView = getListView();
        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
        listView.setMultiChoiceModeListener(this);
    }
}

我看到了两个关于这个的讨论。一个是声明我应该在片段的 onCreate(Bundle savedInstanceState) 方法中使用 setRetainInstance(true) 。另一个说我应该使用 onSaveInstanceState(Bundle bundle)onRestoreInstanceState(Bundle bundle) 方法以某种方式跟踪内容。我想使用 setRetainInstanceState(true) 方法,但像这样将其添加到项目中:

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setRetainInstanceState(true);
}

对我不起作用。我在这里做错了什么?

我建议使用一种略有不同的方法将 Fragment 添加到您的 Activity

在你的 TestActivity class 中,检查 onCreate() 方法中的 Bundle 是否为 null。如果 savedInstanceState 为空,则仅添加 Fragment。这将防止您的 Activity 在设备方向改变时添加相同 Fragment 的另一个实例。

public class TestActivity extends ActionBarActivity {

    protected static final String FRAGMENT_TAG = "TEST";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);

        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        if (savedInstanceState == null) { 

            getFragmentManager().beginTransaction()
                    .replace(R.id.fragment_holder, new TestFragment(), FRAGMENT_TAG)
                    .commit();
        }

    }

}

我建议不要对具有 UI 的 Fragment 使用 setRetainInstance(true) 方法。查看 Whosebug 讨论 here 以了解何时使用 setRetainInstance(true).