#android #android-sqlite
#Android #android-sqlite
Вопрос:
Я пытаюсь отладить свое приложение на реальном устройстве, но я получаю эту ошибку:
ОШИБКА / 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);
}
}
}
Вот XML-файл с командой 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>
Я думаю, что приложение не создает базу данных при первом запуске. Я так думаю, потому что он может найти столбец _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: , при компиляции: ВЫБЕРИТЕ _id, contact_id, contact_name, number_type, contact_number, duration, duration_sum, date, current_time, продолжение, тип, месяц, день, год ИЗ contact_data УПОРЯДОЧИТЬ ПО длительности desc
Я зарегистрировал первый столбец базы данных следующим образом:
Log.i(LOG_TAG, "Cursor(0)" cursor.getColumnName(0));
Он напечатан id
, не _id
. Как вы можете видеть, в инструкции _id
написано. Есть предложения о том, как решить эту проблему?
Комментарии:
1. Полностью удалите приложение с устройства (например, Настройки> Приложения> Управление приложениями) и повторите попытку. Я подозреваю, что ваша база данных уже существовала без
_id
столбца.2. Я сделал, как вы сказали, но ошибка сохраняется. = (
3. @CommonsWare благодарю бога за этот ответ… Я думал, что это проблема с кодированием, но это был такой тривиальный случай!
Ответ №1:
Вы пытаетесь использовать курсор, для которого ТРЕБУЕТСЯ столбец с именем _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
Комментарии:
1.
CursorAdapter
требуется, чтобы столбец вызывался_id
всегда.2. Вы можете использовать псевдоним вместо его создания! Если у вас уже есть столбец _id, но у него другое имя, просто измените имя вашего первичного ключа, используя AS в вашем sql-запросе: { ВЫБЕРИТЕ myprimarykey КАК _id, имя Из таблицы, ГДЕ имя ПОХОЖЕ НА ‘%queryfilter%’; }
3. Основываясь на точке зрения @jcasadellaoller:
db.query("tableName", new String[]{"current_id _id", ...
Это означает, что вы можете использовать существующую таблицу, но запрос будет использовать псевдоним вашего «current_id» в качестве требуемого столбца «_id», так что это будет так, как если бы этот столбец существовал
Ответ №2:
У меня была похожая проблема, потому что я не добавлял столбец _id к аргументу projection, поэтому добавление _id к аргументу projections запроса было решением. (прокомментировано @nobugs)
Пример:
String[] projections = {"_id", "name", "age"};
Cursor cursor = db.query(domainClass.getSimpleName(), projections,
null, null, null, null, null);
Комментарии:
1. Это было решением для меня. Глупый я. Спасибо.
Ответ №3:
Прежде всего удалите приложение, а затем выполните следующие действия:
- Очистите проект
- перестроить проект
- отладьте приложение (Shift F9)
Ответ №4:
CursorAdapter всегда требует наличия _id
столбца. Итак, в список проекций, используемых для создания курсора, вам нужно добавить _id
столбец.
Ответ №5:
Я сделал это и решил свою проблему.
Перед
SELECT id
После
SELECT id as _id