今天在使用ListView 的 addFooterView 的方法时候,遇到了一个问题。当我代码中执行了如下的操作
ListView listView = new ListView(this); listView.addFooterView(mItem); listview.setAdapter(mAdapter); listview.getAdapter();
得到的adapter一直报错,说是类转化错误。后来通过看ListView源码发现了问题所在。
我们看一下addFooterView方法
public void addFooterView(View v, Object data, boolean isSelectable) { final FixedViewInfo info = new FixedViewInfo(); info.view = v; info.data = data; info.isSelectable = isSelectable; mFooterViewInfos.add(info); mAreAllItemsSelectable &= isSelectable; // Wrap the adapter if it wasn't already wrapped. if (mAdapter != null) { if (!(mAdapter instanceof HeaderViewListAdapter)) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter); } // In the case of re-adding a footer view, or adding one later on, // we need to notify the observer. if (mDataSetObserver != null) { mDataSetObserver.onChanged(); } } }
我们看到当我们使用这个方法的时候,其他会把adapter重新创建成为HeaderViewListAdapter,当我们再次得到adapter的时候,它其实已经不是你set 进去的adapter了
网上有好多人说,我们只需要在listview.setAdapter()方法之前使用addFooter方法就可以避免这个问题。我尝试了这种方法,结果还是一样的结果。也就是说,无论你在setAdapter()前后使用这个方法
,对adapter的影响都是一样的,因为我们通过看ListView的setAdapter方法就知道原因了
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; }
我们看到setAdapter里面有上面这句代码。这就说明了,我们无论在哪里使用addFooter方法,其实都会更改adapter
现在我们可以在看看,HeaderViewListAdapter是一个什么东西
public class HeaderViewListAdapter implements WrapperListAdapter, Filterable { private final ListAdapter mAdapter; // These two ArrayList are assumed to NOT be null. // They are indeed created when declared in ListView and then shared. ArrayList<ListView.FixedViewInfo> mHeaderViewInfos; ArrayList<ListView.FixedViewInfo> mFooterViewInfos; 。。。。。。。。。。。。。。。。
它其实也是一个adapter,只不过它里面保存了listview的adapter跟head、foot信息。这样,如果我们想得到当初我们赋给listview的adapter的话,可以考虑从它里面得到。
另外一点需要注意,当我们通过listview.getAdapter()得到adapter的时候,然后通过adapter.getCount的方法得到的item数,是包含了head跟foot的。看下HeaderViewListAdapter 中
getcount方法
public int getCount() { if (mAdapter != null) { return getFootersCount() + getHeadersCount() + mAdapter.getCount(); } else { return getFootersCount() + getHeadersCount(); } }
如果我们想要使用listview.getAdapter()得到我们当初传入的纯净adapter,可以使用如下方法
Adapter a = listView.getAdapter(); ConversationListAdapter adapter = null; if (a instanceof HeaderViewListAdapter) { adapter = (ConversationListAdapter) ((HeaderViewListAdapter) a).getWrappedAdapter(); } else if (a instanceof ConversationListAdapter) { adapter = (ConversationListAdapter) a; } else { android.util.Log.e("zhangshuli", "a=="+a); }
也就是通过instanceof方法,判断我们得到的adapter是原来的,还是被listview改造过的。其中getWrappedAdapter是HeaderViewListAdapter提供的方法,获得的就是纯净adapter