ListView在removeFooterView時報java.lang.ClassCastException錯問題
自古英雄不問出處,奈何我卻不是英雄!
這些天遇到一個很奇怪的問題,很奇怪的問題,很奇怪的問題。重要的事情要說三遍。奇怪的問題大都是在解決之間很奇怪,如果你解決之後你會發現奇怪的是你自己。下面我來說一下我是怎麼奇怪了一把的。
這個奇怪的問題(其實不奇怪)是跟ListView有關係。先說問題和解決辦法:java.lang.Class Cast Exception: android.widget.HeaderViewListAdapter這麼一個異常。那麼你就要看看你的listView.addFooterView是不是放在了listView.setAdaptr後面了。咋辦呢,把它放前面就好了。
下面來說說出問題的願意,這裡有一個HeaderViewListAdapter,首先你回想:這是什麼鬼。沒見過這個類,哪裡來的轉換異常。下面咱們看一下原始碼:
這段程式碼是listView中的原始碼,原始碼有很多行,不過咱們不用看,就這一段就可以。有木有發現HeaderViewListAdapter這個鬼。這裡的if判斷中的mHeaderViewInfos和mFooterViewInfos就是咱們加的listView的header和footer。至於.size()這個方法,咱們暫且理解為你是否為listView add過header或者footer。稍後再來詳細說明一下。想必大家能夠理解了,如果你設定了header或者footer中的其中一個,就會New出一個HeaderViewListAdapter,然後傳入三個引數分別是header和footer和你傳入的adapter。沒設定的話就直接是你建立的那個adapter了。下面看這段原始碼:@Override public void setAdapter(ListAdapter adapter) { if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } }
public boolean removeFooterView(View v) {
if (mFooterViewInfos.size() > 0) {
boolean result = false;
if (mAdapter != null && ((HeaderViewListAdapter) mAdapter).removeFooter(v)) {
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
result = true;
}
removeFixedViewInfo(v, mFooterViewInfos);
return result;
}
return false;
}
看到沒有。listView呼叫的的時候是HeaderViewListAdapter來執行的,由於你沒有先設定header或者footer,導致adapter還是原來的,並不是HeaderViewListAdapter。結果就會出現咱們遇到的類轉換異常了。-------------------這裡是分割線,下面的已經和問題無關,這裡只做拓展----------------------
下面再來說一下上面提到的mHeaderViewInfos.size()和mFooterViewInfos.size()。這裡只是來說明為什麼是.size(),而不是用是否為null來判斷,咱們還是來看原始碼:
/**
* A class that represents a fixed view in a list, for example a header at the top
* or a footer at the bottom.
*/
public class FixedViewInfo {
/** The view to add to the list */
public View view;
/** The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. */
public Object data;
/** <code>true</code> if the fixed view should be selectable in the list */
public boolean isSelectable;
}
private ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList();
private ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList();
看到了吧,這裡是new出來的,咋能用null判斷呢。
再來往下看addHeaderView和addFooterView之後,會走原始碼中的下面這兩個方法:
public void addHeaderView(View v) {
addHeaderView(v, null, true);
}
public void addFooterView(View v) {
addFooterView(v, null, true);
}
大家能看到這兩個方法什麼事都沒幹,只是呼叫了相同方法名的方法,並且傳入了三個引數,其實這兩個方法我們也是可以直接呼叫的,只是不掉用也是沒有任何問題的。下面咱們來說說這三個引數是做什麼的。還是看原始碼:!- -!
public void addHeaderView(View v, Object data, boolean isSelectable) {
final FixedViewInfo info = new FixedViewInfo();
info.view = v;
info.data = data;
info.isSelectable = isSelectable;
mHeaderViewInfos.add(info);
// 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 header view, or adding one later on,
// we need to notify the observer.
if (mDataSetObserver != null) {
mDataSetObserver.onChanged();
}
}
}
由於addFooterView和addHeaderView非常類似,這裡我就補貼程式碼了。咱們主要來說明這三個引數是什麼。
第一個引數:View v,我就不多說了,就是咱們傳進來的View。
第二個引數:Object data,這個就是你header中的資料,你傳入之後在點選header的時候可以用getItem(int)這個方法獲取出來。當然也是可以不傳的,咱們是可以通過別的方法做出和點選同樣效果的,我就不說了,大家都懂得。
第三個引數:boolean
isSelectabe,簡單來說,就是為了讓header或者footer可不可點的,true就是能點選,索引就是0。false就是不能點選了
------------------這裡是分割線,拓展結束------------------
好了就這麼多。希望對大家有用。