許多 Android 開發新手在嘗試動態更新 ListView 某個項目中的控件狀態時,會直接在 Activity 中呼叫 adapter.getView(position, convertView, parent) 取得 View,再透過 findViewById 找到目標控件(如 ImageButton)並修改其狀態(例如切換開關圖片)。然而發現介面完全沒有反應,圖片不會切換,狀態也不會更新。
題主對 ListView 的運作機制有根本性誤解。getView() 是一個 回調方法(帶有 @Override 標註),它的調用者是 ListView 本身,而不是開發者。當某個 Item 需要顯示在螢幕上時,ListView 才會主動呼叫 Adapter 的 getView() 來獲取該 Item 對應的 View,並將其掛載到列表中進行渲染。
開發者手動呼叫 getView() 雖然能拿到一個 View 物件,並對其內部控件做了修改,但這個 View 從未被 ListView 掛載、渲染或顯示。ListView 根本不知道這個 View 的存在,自然也不會重繪介面。
Android 採用「資料驅動視圖」模式。正確流程如下:
private int switchStateResId = R.drawable.switch_on;)。getView() 內部根據這個變數設定 ImageButton 的圖片資源。R.drawable.switch_off)。adapter.notifyDataSetChanged() 通知 ListView 資料已變更,ListView 會重新請求 getView() 並重繪對應項目。// MyAdapter.java
public class MyAdapter extends BaseAdapter {
private int switchStateResId = R.drawable.switch_on; // 預設狀態
public void setSwitchState(boolean isOn) {
this.switchStateResId = isOn ? R.drawable.switch_on : R.drawable.switch_off;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false);
holder = new ViewHolder();
holder.btnSwitch = convertView.findViewById(R.id.btn_switch);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// 關鍵:根據內部狀態變數設定圖片
holder.btnSwitch.setImageResource(switchStateResId);
return convertView;
}
// ... 其他必要方法
}
// Activity 中接收廣播後
public void onBroadcastReceived(boolean state) {
myAdapter.setSwitchState(state); // 1. 更新資料模型
myAdapter.notifyDataSetChanged(); // 2. 通知 UI 刷新
}
切記:不要手動呼叫 getView()。ListView 與 Adapter 之間是解耦的協作關係,UI 更新必須走「修改資料 → 通知 Adapter → ListView 重繪」這條標準流程。這樣才能保證視圖真正更新,也符合 Android 的設計哲學。