關於多執行緒下動態載入ListView資料來源的注意事項
阿新 • • 發佈:2019-02-11
這兩天在編寫使用ListVIew分頁載入資料庫中的資訊時,碰到了一個若隱若現的bug,有時有有時沒有,著實讓人頭大。
其具體實現過程是在子執行緒中獲取需要載入的下一頁資料,然後在runOnUiThread(Runnable action)方法中呼叫adpter.notifyDataSetChanged()來通知listView進行展示更新。部分程式碼如下
new Thread(new Runnable() {
@Override
public void run() {
//從資料庫中獲取下一頁的資料資訊
final List <BlackBean> list = dao.findPart(pageSize,
totalItemCount);
//判斷是否載入到了最後
if (list.size() < pageSize) {
isLoadAll = true;
}
//將獲取到的資料新增到ListView的資料來源中
blacks.addAll(list); //放在這裡會出錯,為什麼。。。。
Log .d(TAG, "這裡添加了資料");
//模擬資料載入的延遲
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//在主執行緒中更新UI
runOnUiThread(new Runnable() {
@Override
public void run() {
//隱藏載入進度條
llLoading.setVisibility(View.GONE);
Log.d(TAG, "這裡更新UI");
//通知介面卡更新資料
adapter.notifyDataSetChanged();
//將正在載入中的狀態置為false
isLoading = false;
}
});
}
}).start();
經過思索和幾次排查將導致異常出現的程式碼鎖定在了blacks.addAll(list);的位置上,試著將這一句移動到runOnUiThread(new Runnable() ) 方法中,與通知adpter更新的方法放在一起。果然錯誤就再也沒有出現了。修改後如下
new Thread(new Runnable() {
@Override
public void run() {
final List<BlackBean> list = dao.findPart(pageSize,
totalItemCount);
if (list.size() < pageSize) {
isLoadAll = true;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
llLoading.setVisibility(View.GONE);
Log.d(TAG, "這裡添加了資料");
blacks.addAll(list);
Log.d(TAG, "這裡更新UI");
adapter.notifyDataSetChanged();
isLoading = false;
}
});
}
}).start();
雖然解決了bug,但還是沒弄懂為什麼會有這種問題。於是進一步思考,根據異常時有時無的現象,猜想可能與執行緒有關,畢竟時間片的排程不受我們控制,可能就在某中情況下的執行緒排程中執行程式碼出現問題。順著這個想法,立刻去百度尋找相關資料。功夫不負有心人,在幾番查詢中終於在一個部落格中發現了類似資訊,並且那個博主對此進行了簡要的解釋,現整理如下。
在子執行緒中更新ListView的資料:多執行緒環境下,在listView快速滑動的時候, 這個執行緒更新了adapter 裡面的資料,但是notifyDataSetChange還沒來得及通知,下一個執行緒又再次更新資料,就會導致了java.lang.IllegalStateException 異常。解決辦法就是:必須在Handler裡面整理將要設定的給adapter的資料,設定adapter資料和notifyDataSetChange,必須在一起完成!必須在一起完成!必須在一起完成!
而我正是在listview滑動監聽中開啟子執行緒來更新資料,所以滑動過快就可能會出現異常,雖然具體導致異常產生的原理沒說,但也算是能解決我關於程式碼方面的疑惑了。特地在此記錄一下。以便回顧。