我有ListFragment
使用标题视图。标题的内容和列表都是从后台任务中获取的。为了不重新获取有关配置更改的数据,我调用setRetainInstance
并将数据保留在片段上。
当配置更改时,将重新创建视图,因此它会删除我之前填充的标题视图。从现在开始我已经掌握了数据,我应该将标题视图重新添加到列表中。
不幸的是,当我尝试这样做时......繁荣!
java.lang.IllegalStateException: Cannot add header view to list -- setAdapter
has already been called.
显然,即使视图被破坏并再次调用onCreateView
,列表的适配器也已设置(或状态被保留),因此无法再次添加标题视图。
如何保留ListView
的标题或重绘它而不在方向更改上重新创建片段?
答案 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
希望它有所帮助;)