Java.lang.IllegalArgumentException:列“_id”不存在。

29

我试图在真实设备上调试我的应用程序,但是出现了以下错误:

ERROR/AndroidRuntime(981):由于java.lang.IllegalArgumentException引起的: 列'_id'不存在

当我在模拟器上测试时,错误没有出现。错误出现在以下代码的最后一行:

adapter = new SimpleCursorAdapter(this, R.layout.list_item, c, new String[] {   
            DataHandlerDB.CONTACT_NAME_COL,
            DataHandlerDB.CONTACT_NUMBER_COL,
            DataHandlerDB.CONTACT_DURATION_COL,
            DataHandlerDB.CONTACT_DATE_COL }, new int[] {
            R.id.contact_name, R.id.phone_number, R.id.duration, R.id.date });

这是我的活动:

public class MyActivity extends Activity {

    private static final String LOG_TAG = "MyActivity";
    private ListView listview;
    private SimpleCursorAdapter adapter;        
    private DataHandlerDB handler;
    private SQLiteDatabase db;
    private OpenHelper helper;
    private Cursor c;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        setContentView(R.layout.main);

        helper = new OpenHelper(this);
        db = helper.getWritableDatabase();
        helper.onCreate(db);
        setBasicContent();
        c.close();
    }   


    @Override
    public void onDestroy(){

        super.onDestroy();
        DataHandlerDB.makeTheSelection(this).close();
        db.close();
        helper.close();

    }

    @Override
    public void onPause(){

        super.onPause();
        DataHandlerDB.makeTheSelection(this).close();
        db.close();
        helper.close();

    }

    @Override
    public void onStop(){

        super.onStop();
        DataHandlerDB.makeTheSelection(this).close();
        db.close();
        helper.close();

    }


    @Override
    protected void onResume(){

        super.onResume();
        setBasicContent();

    }   

    public void setBasicContent() {

        listview = (ListView) findViewById(R.id.list_view); 

        Log.i(LOG_TAG, "listview " + listview);

        c = DataHandlerDB.makeTheSelection(this);

        c.moveToFirst();

        if(db.isOpen())
            Log.i(LOG_TAG, "db is opened");

        Log.i(LOG_TAG, "cursor: " + c.getCount());

        startManagingCursor(c);

        adapter = new SimpleCursorAdapter(this, R.layout.list_item, c, new String[] {   
                DataHandlerDB.CONTACT_NAME_COL,
                DataHandlerDB.CONTACT_NUMBER_COL,
                DataHandlerDB.CONTACT_DURATION_COL,
                DataHandlerDB.CONTACT_DATE_COL }, new int[] {
                R.id.contact_name, R.id.phone_number, R.id.duration, R.id.date });

        Log.i(LOG_TAG, "before setAdapter");
        Toast.makeText(this, "Before setAdapter", Toast.LENGTH_SHORT).show();

        listview.setAdapter(adapter);

        db.close();

        if(db.isOpen()){

            Log.i(LOG_TAG, "db is opened.");

        }

        if(!c.isClosed()){

            Log.i(LOG_TAG, "cursor is opened");

        }           
    }       
}

查询并返回Cursor的函数在DataHandlerDB类中:

public class DataHandlerDB {

private static final String DATABASE_NAME = "calls.db";
private static final int DATABASE_VERSION = 1;

protected static String CONTACT_NAME_COL = "contact_name";
protected static String CONTACT_NUMBER_COL = "contact_number";
protected static String CONTACT_DURATION_COL = "duration";
protected static String CONTACT_DATE_COL = "date";
protected static String CONTACT_MONTH_COL = "month";

// create the DB
public static SQLiteDatabase createDB(Context ctx) {
    OpenHelper helper = new OpenHelper(ctx);
    SQLiteDatabase db = helper.getWritableDatabase();
    helper.onCreate(db);
    helper.onOpen(db);
    db.close();
    return db;
}

public static Cursor makeTheSelection(Context ctx) {

    OpenHelper helper = new OpenHelper(ctx);
    SQLiteDatabase db = helper.getWritableDatabase();

    Cursor cursor = db.query(TABLE_NAME_2, null, null, null, null, null,
            "duration desc");

    cursor.moveToFirst();
    db.close();

    return cursor;
}
    // class OpenHelper
public static class OpenHelper extends SQLiteOpenHelper {

    private final Context mContext;

    OpenHelper(Context context) {

        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.mContext = context;

    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.i(LOG_TAG, "entrou no onCreate");
        String[] sql = mContext.getString(
                R.string.MyAppDatabase_OnCreate).split("\n");

        db.beginTransaction();

        try {
            execMultipleSQL(db, sql);
            db.setTransactionSuccessful();
        } catch (SQLException e) {

            Log.e("Error creating tables and debug data", e.toString());
            throw e;

        } finally {
            db.endTransaction();

        }
    }

    private void execMultipleSQL(SQLiteDatabase db, String[] sql) {

        for (String s : sql) {

            if (s.trim().length() > 0) {

                db.execSQL(s);
            }
        }

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

         Log.w("MyDB Database",
         "Upgrading database, this will drop tables and recreate.");
         db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db);

    }

    @Override
    public void onOpen(SQLiteDatabase db) {

        super.onOpen(db);
    }
}
}

这是带有SQL命令的XML文件:

<string name="MyAppDatabase_OnCreate">
    "CREATE TABLE IF NOT EXISTS contact_data(_id INTEGER PRIMARY KEY AUTOINCREMENT, contact_id INTEGER, contact_name VARCHAR(50), number_type VARCHAR(50), contact_number VARCHAR(50), duration TIME, duration_sum TIME, date DATE, current_time TIME, cont INTEGER, type VARCHAR, month VARCHAR(50), day VARCHAR(50), year VARCHAR(50));"
</string>

我认为应用程序在第一次启动时没有创建数据库。我这样认为是因为它可以找到列_id,但在XML代码中明确写入了使用_id列创建它。我还认为,因为我已经明确在SELECT方法中编写了列,包括_id。我是这样做的:

Cursor cursor = db.query(TABLE_NAME_2, 
                new String[]{
                "_id", 
                "contact_id", 
                "contact_name", 
                "number_type", 
                "contact_number", 
                "duration", 
                "duration_sum", 
                "date", 
                "current_time", 
                "cont", "type", 
                "month", 
                "day", 
                "year"}, null, null, null, null,
                "duration desc");

在这种情况下,我收到的错误几乎相同:

导致问题的原因是: android.database.sqlite.SQLiteException: 找不到列: _id: , 在编译以下查询时出现问题: SELECT _id, contact_id, contact_name, number_type, contact_number, duration, duration_sum, date, current_time, cont, type, month, day, year FROM contact_data ORDER BY duration desc

我已经将数据库的第一列记录如下:

Log.i(LOG_TAG, "Cursor(0)" + cursor.getColumnName(0));

它打印了id,而不是_id。正如您所看到的,语句中写有_id。 有没有关于如何解决这个问题的建议?


2
从设备中完全卸载该应用程序(例如,设置>应用程序>管理应用程序),然后重试。我怀疑您的数据库已经存在,但没有“_id”列。 - CommonsWare
我按照你说的做了,但错误仍然存在。=( - rogcg
@CommonsWare 感谢您的答案...我以为这是一个编码问题,但实际上它只是一个微不足道的情况! - Bao Thai
5个回答

45

你正在尝试使用一个需要名为_id的列的光标。只需编辑您的表创建语句并添加名为_id的列即可。

它的声明类似于这样:

_id INTEGER PRIMARY KEY AUTOINCREMENT

添加这个代码,然后您就可以使用它了。我相信这是使用SimpleCursorAdapter所必需的要求。

更新

"CREATE TABLE IF NOT EXISTS contact_data( _id INTEGER PRIMARY KEY AUTOINCREMENT, contact_id INTEGER, contact_name VARCHAR(50), number_type VARCHAR(50), contact_number VARCHAR(50), duration TIME, duration_sum TIME, date DATE, current_time TIME, cont INTEGER, type VARCHAR, month VARCHAR(50), day VARCHAR(50), year VARCHAR(50));"

解决方案: 在左圆括号 '(' 和 _id 之间添加一个空格


8
CursorAdapter йңҖиҰҒе§Ӣз»ҲеӯҳеңЁдёҖдёӘеҗҚдёә _id зҡ„еҲ—гҖӮ - tread
3
您可以使用别名(alias)而不是创建主键(primary key)!如果您已经有了_id列但列名不同,只需在SQL查询中使用AS更改主键名称:{ SELECT myprimarykey AS _id, name FROM Table WHERE name LIKE '%queryfilter%'; }。 - Joan Casadellà
2
在 @jcasadellaoller 的基础上进行扩展:db.query("tableName", new String[]{"current_id _id", ...这意味着您可以使用现有的表,但查询将别名您的 "current_id" 作为所需的 "_id" 列,因此就好像该列存在一样。 - Prof

15

由于我没有将_id列添加到投影参数中,所以我遇到了类似的问题,因此在查询的投影参数中添加_id是解决方案。(由@nobugs评论)

 String[] projections = {"_id", "name", "age"};

 Cursor cursor = db.query(domainClass.getSimpleName(), projections, 
     null, null, null, null, null);

3
这对我来说是解决方案。我太傻了。谢谢。 - Chad Mx

2

首先卸载应用程序,然后执行以下步骤:

  1. 清理项目
  2. 重新构建项目
  3. 调试应用程序(Shift+F9)

0

我做了这个并解决了我的问题。

之前

SELECT id

之后

SELECT id as _id


0

CursorAdapter总是需要一个名为_id的列存在。因此,在用于创建Cursor的投影列表中,您需要添加_id列。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接