【问题标题】:How to maintain ListView fragment state after orientation/configuration change?方向/配置更改后如何维护 ListView 片段状态?
【发布时间】:2015-03-30 12:43:10
【问题描述】:

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

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

这是我的活动:

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 类,还有杂项。内容已删除:

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 仍将被重新创建,并且视图被破坏。如果您确实想保留原始视图,则可以尝试通过在清单定义中使用 configChanges 属性来保留 Activity 实例。但是,这不是一个好主意,除非您真的需要它,而且它也不可靠,因为您只能选择不会重新启动 Activity 的特定配置更改,并且 Activity 可能仍会因应用程序进程本身被杀死并重新创建。
  • 出于您所说的原因,我想避免使用 configChanges 属性。不过还是谢谢。

标签: android android-fragments android-listview android-listfragment


【解决方案1】:

我建议采用稍微不同的方法将Fragment 添加到您的Activity

在您的 TestActivity 类中,检查 onCreate() 方法中的 Bundle 是否为空。如果 savedInstanceState 为 null,则仅添加 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) 方法。查看 StackOverflow 讨论 here,了解何时使用 setRetainInstance(true)

【讨论】:

  • 在这种情况下,我是否需要在每次轮换时调用 setListAdapter(data)?我在我的应用程序中模拟了上述设置,但我只看到活动指示器/微调器和 Loading... 显示。但是,在我快速制作的一个示例应用程序中,它确实在 onActivityCreated() 中调用了 setListAdapter(),这似乎有效(至少它保持了我在列表中的位置 OK,还不确定列表项的选择状态)。
  • 好的,新的更新。我有你的代码在我的应用程序中工作。我不确定我做错了什么,但我想现在这无关紧要。我还注意到 CAB 标题没有正确保存,但我能够在 onPrepareActionMode 方法中找回它,因为活动知道它以前是打开的,这很好。
  • 您是否偶然在 Activity 中覆盖了 onSaveInstanceState() 而没有调用 super 方法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 2019-09-06
相关资源
最近更新 更多