1. 程式人生 > >Android知識總結:ListView 出現IndexOutOfBoundsException異常

Android知識總結:ListView 出現IndexOutOfBoundsException異常

背景

今天在整理友盟統計bug時,發現有幾個bug集中在首頁ListView的Adapter上,具體翻來,大概是說ListView中資料出現越界。具體錯誤日誌大概如下:
java.lang.IndexOutOfBoundsException: Invalid index 4, size is 0
    at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
    at java.util.ArrayList.get(ArrayList.java:304)
    ... ...

也就是說,我們的ListView中的資料列表長度為0,但是我們索引到了index為4的資料。臥槽,ListView陣列的內容不是由Adapter管理的嗎,為什麼此處會產生越界?

翻閱了一些網頁,大家都提到ListView是非同步的,也有些說法是不要使用Adapter的notifyDataSetChanged方法,我也開始懷疑是不是notifyDataSetChanged方法使用的不對。總之,想要復現這個bug似乎並不是很容易。

既然復現不了,那麼我們就再捋一下程式碼,看看能不能找到什麼線索,程式碼中請求資料和重新整理資料的流程大概如下:

mDataList.clear();//清空列表

final GsonRequest<HomeJson> request = new GsonRequest<>(url, HomeBean.class, psd,
       new Response.Listener<HomeBean>() {
       @Override
       public void onResponse(HomeJson response) {
       if
(請求資料成功) { //更新資料列表 mDataList = response.getData(); //進行notifyDataSetChanged showView(); ... ...

我們的流程是,先清空列表,然後進行網路載入,當載入成功後將資料賦值給Adapter,然後notifyDataSetChanged。那麼,請求網路過程中呢…… 當然還顯示頁面上的ListView了,那麼,當請求網路的過程中有人滾動螢幕呢,我們ListView中的資料已經清空,那麼Adapter的getView中將無法拿到要顯示的資料。這樣,就出現了陣列長度為0,但是索引index為大於0的數字的情況。

這也正是體現了ListView的非同步,雖然資料變化了,但是ListView本身並不知道,所以我們需要及時呼叫notifyDataSetChanged,告訴ListView資料變化啦,你顯示的時候要用新資料了。

我們可以進行如下修改:

... ... 
mDataList.clear();
//更新資料列表               
mDataList = response.getData();
//進行notifyDataSetChanged
showView(); 
... ...

我們在網路請求完畢後刪除List的資料,然後直接進行notifyDataSetChanged,這樣始終保持ListView與資料列表是同步的,就不會出現資料列表與index不同步而出現IndexOutOfBoundsException的問題了。