方向/配置更改后如何维护 ListView 片段状态?
Posted
技术标签:
【中文标题】方向/配置更改后如何维护 ListView 片段状态?【英文标题】:How to maintain ListView fragment state after orientation/configuration change? 【发布时间】:2015-03-30 12:43:10 【问题描述】:我的应用程序中有一个 ListView 片段遇到了一些问题。
-
当我滚动到列表视图中的特定元素,然后旋转设备时,列表视图会重置到列表顶部。
当我在列表视图中进入多选模式,然后旋转设备时,选定的列表项会重置。
这是我的活动:
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_
android:layout_
android:orientation="vertical" >
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_
android:layout_
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize" >
</android.support.v7.widget.Toolbar>
<FrameLayout
android:id="@+id/fragment_holder"
android:layout_
android:layout_ />
</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 属性。不过还是谢谢。
【参考方案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)
方法。查看 *** 讨论 here,了解何时使用 setRetainInstance(true)
。
【讨论】:
在这种情况下,我是否需要在每次轮换时调用 setListAdapter(data)?我在我的应用程序中模拟了上述设置,但我只看到活动指示器/微调器和 Loading... 显示。但是,在我快速制作的一个示例应用程序中,它确实在 onActivityCreated() 中调用了 setListAdapter(),这似乎有效(至少它保持了我在列表中的位置 OK,还不确定列表项的选择状态)。 好的,新的更新。我有你的代码在我的应用程序中工作。我不确定我做错了什么,但我想现在这无关紧要。我还注意到 CAB 标题没有正确保存,但我能够在onPrepareActionMode
方法中找回它,因为活动知道它以前是打开的,这很好。
您是否偶然在 Activity 中覆盖了 onSaveInstanceState() 而没有调用 super 方法?以上是关于方向/配置更改后如何维护 ListView 片段状态?的主要内容,如果未能解决你的问题,请参考以下文章