在開發 Android 購物車功能時,使用 ListView 展示商品列表,每個 Item 包含加號、減號按鈕及選中狀態。開發者遇到經典問題:使用 ViewHolder 模式後,點擊加減按鈕雖然數據更新正確,但界面顯示的 Item 卻錯位了。不使用 ViewHolder 則會導致列表滑動卡頓。這是典型的 ListView 適配器優化難題。
原代碼中在 getView 方法內部創建了 MyListener 並傳入 position,但由於 ViewHolder 復用機制,當 ListView 回收視圖時,position 參數已不再對應當前顯示的數據位置,導致監聽器持有過期的位置信息。此外,代碼中混合使用了匿名內部類和自定義監聽器類,邏輯混亂,且在監聽器內部直接操作 viewHolder 靜態變量,進一步加劇了錯亂。
參考最佳回答中的 ShopItemAdapter 實現,核心思想是:
public class ShopCartAdapter extends BaseAdapter {
private Context context;
private List<CartItem> dataList;
private LayoutInflater inflater;
private Handler uiHandler; // 用於通知總價更新
static class ViewHolder {
ImageView ivProduct, ivSelect, ivReduce, ivAdd;
TextView tvName, tvPrice, tvCount, tvSubtotal;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.item_cart, parent, false);
// 初始化所有視圖引用
holder.ivReduce = convertView.findViewById(R.id.btn_reduce);
holder.ivAdd = convertView.findViewById(R.id.btn_add);
// ... 其他視圖
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final CartItem item = dataList.get(position);
// 綁定數據
holder.tvName.setText(item.getName());
holder.tvPrice.setText(String.format("¥%.2f", item.getPrice()));
holder.tvCount.setText(String.valueOf(item.getCount()));
// 根據選中狀態更新 UI
updateItemUI(holder, item);
// 關鍵:為每個按鈕設置監聽器,捕獲最終的 position
holder.ivAdd.setOnClickListener(v -> {
item.setCount(item.getCount() + 1);
notifyDataSetChanged();
uiHandler.sendEmptyMessage(MSG_UPDATE_TOTAL);
});
holder.ivReduce.setOnClickListener(v -> {
if (item.getCount() > 1) {
item.setCount(item.getCount() - 1);
notifyDataSetChanged();
uiHandler.sendEmptyMessage(MSG_UPDATE_TOTAL);
}
});
holder.ivSelect.setOnClickListener(v -> {
item.setSelected(!item.isSelected());
notifyDataSetChanged();
uiHandler.sendEmptyMessage(MSG_UPDATE_TOTAL);
});
return convertView;
}
}
final int position,確保監聽器執行時位置正確findViewById 調用,滑動流暢採用此模式可徹底解決購物車列表的按鈕監聽錯位問題,同時保證流暢的用戶體驗。