本文参考:http://blog.csdn.net/androiddevelop/article/details/8474939
异常提示:Java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.
产生原因:addHeaderView()调用在setAdapter()之后,并且该代码运行在Android4.3之前的系统版本。Android SDK与API Level对应表
我们来看看(Android4.3)API-18 和 (Android4.2)API-17的Listview代码片段:
API-18
public void addHeaderView(View v, Object data, boolean isSelectable) {
02. final FixedViewInfo info = new FixedViewInfo();
03. info.view = v;
04. info.data = data;
05. info.isSelectable = isSelectable;
06. mHeaderViewInfos.add(info);
07.
08. // Wrap the adapter if it wasn't already wrapped.
09. if (mAdapter != null) {
10. if (!(mAdapter instanceof HeaderViewListAdapter)) {
11. mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
12. }
13.
14. // In the case of re-adding a header view, or adding one later on,
15. // we need to notify the observer.
16. if (mDataSetObserver != null) {
17. mDataSetObserver.onChanged();
18. }
19. }
20.}
API-17
public void addHeaderView(View v, Object data, boolean isSelectable) {
02.
03. if (mAdapter != null && ! (mAdapter instanceof HeaderViewListAdapter)) {
04. throw new IllegalStateException(
05. "Cannot add header view to list -- setAdapter has already been called.");
06. }
07.
08. FixedViewInfo info = new FixedViewInfo();
09. info.view = v;
10. info.data = data;
11. info.isSelectable = isSelectable;
12. mHeaderViewInfos.add(info);
13.
14. // in the case of re-adding a header view, or adding one later on,
15. // we need to notify the observer
16. if (mAdapter != null && mDataSetObserver != null) {
17. mDataSetObserver.onChanged();
18. }
19.}
在API-17中,假如adapter不为空,则会直接抛出异常,而在API-18中则做了相关的优化。
再看一下setAdapter()方法部分源码:
public void More ...setAdapter(ListAdapter adapter) {
...此处省略部分代码...
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
...此处省略部分代码...
}
建议
按照正常的人逻辑:先添加header,在4.3以前版本,由于此时mAdapter = null,所以不会走抛异常逻辑。再设置adapter,此时看adapter的源码,此时的adapter成为了HeaderListAdapter了,我们在此时可以移除掉header。
等在访问网络成功之后,再去添加header,此时走进addHeader的源码,虽然if语句中mAdapter!=null条件满足,但是后面条件mAdapter已经是HeaderListAdapter类型了,条件不满足,也不会走抛异常逻辑。此时就是可行的。
总结:先添加header或者footer,在setAdapter之后再移除掉header或者footer。在访问网络成功之后,再去添加header或者footer即可。