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

Android GridView 多實例點擊事件取值錯誤:閉包陷阱與解決方案

     編輯:程式設計綜合問答

動態建立多個 GridView 並在同一個 Activity 中顯示時,若直接使用成員變數 gridView 於 OnItemClickListener 內取值,會發生「點擊任一 GridView 都取到最後一個的資料」或「下標越界」的經典 Bug。

錯誤代碼片段

// 成員變數
GridView gridView;

// 迴圈建立多個 GridView
for (...) {
    gridView = new MyGridView(...);
    gridView.setAdapter(sAdapter);
    gridView.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
            // ❌ 這裡用的是外部成員變數 gridView,迴圈結束時指向最後一個實例
            HashMap<String,String> map = (HashMap) gridView.getItemAtPosition(pos);
            ...
        }
    });
}

根因:Java 匿名內部類捕獲的是變數引用,而非當時的值

迴圈結束後,gridView 指向最後一個實例,所有 Listener 共用同一個引用。

解決方案:自定義 Listener 捕獲當前 GridView 實例

class MyOnItemClickListener implements AdapterView.OnItemClickListener {
    private final GridView gv;
    public MyOnItemClickListener(GridView gv) { this.gv = gv; }
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
        HashMap<String,String> map = (HashMap) gv.getItemAtPosition(pos); // ✅ 使用捕獲的實例
        String btnText = map.get("fenlei_btnlist_btn_text");
        // 後續跳轉邏輯...
    }
}

// 使用時
gridView.setOnItemClickListener(new MyOnItemClickListener(gridView));

替代方案(Java 8+ / Android API 24+)

// 使用 final 或 effectively final 區域變數
final GridView currentGridView = gridView; // 迴圈內部區域變數
gridView.setOnItemClickListener((parent, view, pos, id) -> {
    HashMap<String,String> map = (HashMap) currentGridView.getItemAtPosition(pos);
    ...
});

關鍵原則

  • 事件監聽器需綁定「當時」的目標物件,避免共用可變成員變數。
  • 優先使用區域 final 變數或建構子傳遞,明確捕獲語意。
  • 大量動態 View 時,考慮 RecyclerView + ViewHolder 模式替代 GridView,效能與記憶體表現更優。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved