ListView setAdapter has already been called 异常

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32059827/article/details/75022068

本文参考: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 SDKAPI Level对应表

我们来看看(Android4.3API-18 和 (Android4.2API-17Listview代码片段:

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即可。





猜你喜欢

转载自blog.csdn.net/qq_32059827/article/details/75022068
今日推荐