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

Android ListView 獲取項目真實 ID 而非位置:CursorAdapter 完整指南

     編輯:程式設計綜合問答

ListView 點擊事件回傳的 position 僅為視圖位置,非資料庫主鍵 ID。本文針對您使用 SimpleCursorAdapter 的場景,詳細講解如何正確獲取資料庫 _id,並解析您自行找到的解決方案。

核心問題:position ≠ _id

您的原始代碼:

@Override
public void onListItemClick(ListView parent, View view, int position, long id) {
    Intent intent = new Intent(this, VSDetailsActivity.class);
    intent.putExtra("com.manager.boot.r1223." + BaseColumns._ID, position); // 錯誤:傳遞 position
    startActivity(intent);
}

position 是列表可見項目索引 (0-based),會隨排序、過濾、刪除而變化。_id 是資料庫主鍵,唯一且穩定。

正確解決方案:透過 Cursor 獲取 _id

您找到的解決方案完全正確:

@Override
public void onListItemClick(ListView parent, View view, int position, long id) {
    Cursor cursor = (Cursor) adapter.getItem(position); // 關鍵:獲取該位置的 Cursor
    Intent intent = new Intent(this, VSDetailsActivity.class);
    intent.putExtra("com.manager.boot.r1223." + BaseColumns._ID, 
        cursor.getInt(cursor.getColumnIndex("_id"))); // 獲取真實 _id
    startActivity(intent);
}

深度解析:為什麼這樣寫是正確的?

  1. adapter.getItem(position):CursorAdapter 重寫此方法回傳對應位置的 Cursor (已移動到該行)
  2. cursor.getColumnIndex("_id"):獲取 _id 欄位索引 (建議用常數 BaseColumns._ID)
  3. cursor.getInt(...):讀取長整數主鍵值

替代方案:直接使用 onListItemClick 的 id 參數

前提:您的 Cursor 查詢必須包含 _id 欄位,且 Adapter 建構時正確關聯:

// 查詢必須包含 _id
String[] from = { "name", "desc", "status", "path", "folder", BaseColumns._ID };
// Adapter 會自動將 _id 映射到 id 參數
// 於是 onListItemClick 的 long id 即為 _id 值
@Override
public void onListItemClick(ListView parent, View view, int position, long id) {
    Intent intent = new Intent(this, VSDetailsActivity.class);
    intent.putExtra("com.manager.boot.r1223." + BaseColumns._ID, id); // 直接使用
    startActivity(intent);
}

這是 CursorAdapter 設計意圖:id 參數即為 Cursor 中 _id 欄位值。

為何您的代碼無法直接用 id 參數?

檢查您的查詢:

String[] from = { "name", "desc", "status", "path", "folder", BaseColumns._ID };

這看起來是正確的。可能原因:

  • Cursor 未包含 _id (別名不對、查詢語句漏選)
  • Adapter 非 CursorAdapter 子類 (但您用的是 VSsimplecursoradapter 繼承 SimpleCursorAdapter)
  • Cursor 未正確關閉/重查導致位置錯位

建議加入防禦性檢查:

Cursor cursor = (Cursor) adapter.getItem(position);
if (cursor != null && !cursor.isClosed()) {
    int idIndex = cursor.getColumnIndex(BaseColumns._ID);
    if (idIndex >= 0) {
        long realId = cursor.getLong(idIndex);
        // 使用 realId
    }
}

現代化建議:遷移至 RecyclerView + Room

ListActivity、SimpleCursorAdapter、startManagingCursor 均已棄用。現代架構:

// Room Dao
@Query("SELECT * FROM mfs ORDER BY name")
Flow> getAllItems();

// Fragment/ViewModel
itemsFlow.collect { items ->
    adapter.submitList(items)
}

// Adapter 點擊
adapter.setOnItemClickListener(item -> {
    Intent intent = new Intent(context, DetailActivity.class);
    intent.putExtra("ITEM_ID", item.id); // 直接用資料類別的 id
    startActivity(intent);
});

總結

獲取 ListView 項目真實 ID 的標準做法:

  1. CursorAdapter:使用 adapter.getItem(position) 獲取 Cursor,再讀取 _id 欄位 (您的解決方案)
  2. 正確配置時:直接使用 onListItemClick 的 long id 參數
  3. 現代開發:遷移至 RecyclerView + Room,資料模型直接攜帶 ID,徹底避免位置與 ID 混淆

您的自行解決方案正確且符合當時 API 設計模式。建議新專案直接採用現代架構,從根本消除此類問題。

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