首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android BaseAdapter 中 ArrayList.size() 導致崩潰?核心原因:列表引用未初始化或非線程安全

     編輯:程式設計綜合問答

常見崩潰現場

public class MyAdapter extends BaseAdapter {
    private ArrayList<Item> mList; // 僅聲明,未 new
    
    @Override public int getCount() {
        return mList.size(); // NPE:mList 為 null
    }
    // ...
}

核心原因排查清單

  1. 未初始化:mList = new ArrayList<>() 缺失,或構造函數未賦值。
  2. 傳入引用後被外部清空:構造函數 this.mList = list 直接持有外部引用,外部 list.clear() 導致內部同步變空。
  3. 非線程安全:後台線程修改 mList,UI 線程 getCount() 讀取,發生並發修改異常或讀到中間態。
  4. 泛型擦除導致類型不匹配:極少見,若混用原始類型 ArrayList 可能 ClassCastException。

最佳實踐模板

public class MyAdapter extends BaseAdapter {
    private final List<Item> mList = new ArrayList<>(); // 1. 宣告即初始化,final 防止誤重賦值
    private final LayoutInflater mInflater;
    
    public MyAdapter(Context context) {
        mInflater = LayoutInflater.from(context);
    }
    
    // 2. 安全設值:防禦性複製 + 主線程
    public void setData(@Nullable List<Item> data) {
        if (data == null) { mList.clear(); notifyDataSetChanged(); return; }
        // 若在非主線程,用 runOnUiThread / Handler.post
        mList.clear();
        mList.addAll(data); // 複製內容,斷開外部引用
        notifyDataSetChanged();
    }
    
    @Override public int getCount() { return mList.size(); }
    @Override public Item getItem(int pos) { return mList.get(pos); }
    @Override public long getItemId(int pos) { return pos; }
    @Override public View getView(int pos, View cv, ViewGroup p) { /* ... */ }
}

進階:DiffUtil + ListAdapter (RecyclerView 時代)

若專案已遷移 RecyclerView,請直接使用 ListAdapter + DiffUtil.ItemCallback,框架自動處理列表差分、動畫、線程安全,徹底告別 BaseAdapter 手動管理痛點。

快速自查步驟

  1. 斷點/日誌確認 getCount() 進入時 mList 是否為 null。
  2. 檢查構造函數與 setData() 是否正確賦值。
  3. 搜尋全專案 .clear()、= null 對該列表的操作。
  4. 若多線程,加 synchronized 或改用 CopyOnWriteArrayList(讀多寫少)。

「普通數組 .length 沒問題,ArrayList .size() 崩」 99% 是 引用未初始化或被外部清空。按模板重寫即可根治。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved