ListView的标题视图在配置更改时销毁

时间:2013-01-09 14:56:47

标签: android android-listview android-fragments android-orientation

我有ListFragment使用标题视图。标题的内容和列表都是从后台任务中获取的。为了不重新获取有关配置更改的数据,我调用setRetainInstance并将数据保留在片段上。

当配置更改时,将重新创建视图,因此它会删除我之前填充的标题视图。从现在开始我已经掌握了数据,我应该将标题视图重新添加到列表中。

不幸的是,当我尝试这样做时......繁荣!

java.lang.IllegalStateException: Cannot add header view to list -- setAdapter 
has already been called.

显然,即使视图被破坏并再次调用onCreateView,列表的适配器也已设置(或状态被保留),因此无法再次添加标题视图。

如何保留ListView的标题或重绘它而不在方向更改上重新创建片段?

3 个答案:

答案 0 :(得分:1)

这是预期的行为,请查看Android源代码here以获取有关API 17的指导,但实际上任何人都会这样做。相关部分是:

  

添加固定视图以显示在列表顶部。如果addHeaderView是   不止一次调用,视图将按照它们的顺序出现   添加。使用此调用添加的视图可以在需要时获得焦点。注意:   在调用setAdapter之前调用它。这是ListView可以包装的   提供了一个也会占据页眉和页脚的光标   视图。

public void addHeaderView(View v, Object data, boolean isSelectable) {

    if (mAdapter != null && ! (mAdapter instanceof HeaderViewListAdapter)) {
        throw new IllegalStateException(
            "Cannot add header view to list -- setAdapter has already been" +
            "called.");  // Edit: SK9 wrapped this.
    }

    FixedViewInfo info = new FixedViewInfo();
    info.view = v;
    info.data = data;
    info.isSelectable = isSelectable;
    mHeaderViewInfos.add(info);

    // in the case of re-adding a header view, or adding one later on,
    // we need to notify the observer
    if (mAdapter != null && mDataSetObserver != null) {
        mDataSetObserver.onChanged();
    }
}

当您再次添加标头并引发异常时,适配器不为空。要解决您的问题,以下几行中的内容就可以了:

setListAdapter(null);
getListView().addHeaderView(mHeader);
setListAdapter(new MyAdapter(getActivity(), items));

我甚至不会将此归类为解决方法。我遇到了同样的问题,这对我有用。

显然,页脚的处理方式截然不同,请参阅here

public void addFooterView(View v, Object data, boolean isSelectable) {

    // NOTE: do not enforce the adapter being null here, since unlike in
    // addHeaderView, it was never enforced here, and so existing apps are
    // relying on being able to add a footer and then calling setAdapter to
    // force creation of the HeaderViewListAdapter wrapper

    FixedViewInfo info = new FixedViewInfo();
    info.view = v;
    info.data = data;
    info.isSelectable = isSelectable;
    mFooterViewInfos.add(info);

    // in the case of re-adding a footer view, or adding one later on,
    // we need to notify the observer
    if (mAdapter != null && mDataSetObserver != null) {
        mDataSetObserver.onChanged();
    }
}

答案 1 :(得分:0)

这是一个知道问题,但您可以像这样解决它:

在设置适配器之前添加标头并将其删除

答案 2 :(得分:0)

是的,这是一个已知问题,但可以通过正确的方法避免。 似乎存在类似于您的问题的解决方案。
这些家伙找到了解决方法:setSelected in OnItemClick in ListView
希望它有所帮助;)