public class MyAdapter extends BaseAdapter {
private ArrayList<Item> mList; // 僅聲明,未 new
@Override public int getCount() {
return mList.size(); // NPE:mList 為 null
}
// ...
}
mList = new ArrayList<>() 缺失,或構造函數未賦值。this.mList = list 直接持有外部引用,外部 list.clear() 導致內部同步變空。mList,UI 線程 getCount() 讀取,發生並發修改異常或讀到中間態。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) { /* ... */ }
}
若專案已遷移 RecyclerView,請直接使用 ListAdapter + DiffUtil.ItemCallback,框架自動處理列表差分、動畫、線程安全,徹底告別 BaseAdapter 手動管理痛點。
getCount() 進入時 mList 是否為 null。setData() 是否正確賦值。.clear()、= null 對該列表的操作。synchronized 或改用 CopyOnWriteArrayList(讀多寫少)。「普通數組 .length 沒問題,ArrayList .size() 崩」 99% 是 引用未初始化或被外部清空。按模板重寫即可根治。