2011-04-27 28 views
23

Estoy tratando de depurar mi aplicación en un dispositivo real, pero me sale este error:java.lang.IllegalArgumentException: columna no existe '_id'

ERROR/AndroidRuntime(981): Caused by: java.lang.IllegalArgumentException: column '_id' does not exist

cuando estoy probando en un emulador, el error no aparece El error se da en la última línea del siguiente código:

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 }); 

Aquí está mi actividad:

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"); 

     }   
    }  
} 

La función que las consultas y devuelve el Cursor está en la clase 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); 
    } 
} 
} 

Aquí está el archivo XML con el comando SQL:

<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> 

Creo que la aplicación no está creando la base de datos cuando se inicia por primera vez. Creo que sí porque puede encontrar la columna _id, pero está escrita explícitamente en el código XML para crearla con la columna _id. También creo que porque he escrito explícitamente las columnas en el método SELECT, incluido el _id. Lo hice así:

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"); 

En este caso, el error que recibo es casi el mismo:

Caused by: android.database.sqlite.SQLiteException: no such column: _id: , while compiling: 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

He inscrito la primera columna de la base de datos de este modo:

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

Imprimió id, no _id. Como puede ver, hay _id escrito en la declaración. ¿Alguna sugerencia sobre cómo resolver este problema?

+0

Desinstale completamente la aplicación del dispositivo (por ejemplo, Configuración> Aplicaciones> Administrar aplicaciones) y vuelva a intentarlo. Sospecho que su base de datos ya existía sin la columna '_id'. – CommonsWare

+0

Hice lo que dijo, pero el error persiste. = ( – rogcg

Respuesta

37

Está intentando utilizar un cursor que REQUIERE una columna llamada _id. Es tan simple como editar la declaración de creación de la tabla y agregar una columna llamada _id.

Su Declartion ve algo como esto:

_id INTEGER PRIMARY KEY AUTOINCREMENT 

Añadir esto y a continuación, será capaz de utilizarlo. Creo que este es un requisito que se requiere para usar un SimpleCursorAdapter.

ACTUALIZACIÓN

"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));" 

Solución: añadir un espacio entre el paréntesis izquierdo '(' y _ID

+4

'CursorAdapter' requiere una columna llamada' _id' always. – surfer190

+1

¡Puede usar alias en lugar de crearlo! Si ya tiene su columna _id pero tiene otro nombre, simplemente cambie su nombre de clave principal usando AS en su consulta SQL: {SELECCIONE myprimarykey AS _id, nombre FROM Table WHERE name LIKE '% queryfilter%';} – jcasadellaoller

9

he tenido problema similar porque no estaba añadiendo el _id columna al argumento de proyección, por lo tanto, agregue _id al proyecto El argumento de la consulta fue la solución.(comentado por @nobugs)


Ejemplo:

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

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

Esta fue la solución para mí. Tonto de mí. Gracias. –

2

En primer lugar desinstalar la aplicación, y luego siga los pasos siguientes:

  1. Limpiar el proyecto
  2. reconstrucción El proyecto
  3. depura la aplicación (Shift + F9)
Cuestiones relacionadas