方向/配置更改后如何维护 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 片段状态?的主要内容,如果未能解决你的问题,请参考以下文章

后堆栈中的配置更改片段现在正在共享 FrameLayout?

返回片段后ListView为空

如何防止在方向更改时重新创建片段寻呼机中的片段?

如何在屏幕方向更改时附加片段?

如何更改片段的大小?

配置更改后片段丢失过渡动画