以下是我要创建的表的结构:
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "WidgetDatabase.db";
private static final String TABLE_WIDGET = "widgets";
private static final String KEY_CITY = "city";
private static final String KEY_ID = "widgetid";
public WidgetPrefs(Context context) {
super(context , DATABASE_NAME , null , DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_QUESTION_TABLE = "CREATE TABLE " + TABLE_WIDGET + " (" +
KEY_CITY + " TEXT," +
KEY_ID + " INTEGER," +
"PRIMARY KEY(" + KEY_ID + ")" +
");";
db.execSQL(CREATE_QUESTION_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_WIDGET);
// Create tables again
onCreate(db);
}
现在,当我尝试运行这样的函数时:
public String getCity(int widgetId) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT " + KEY_CITY + " FROM " + TABLE_WIDGET + ";", null);
if (cursor != null) {
cursor.moveToFirst();
if (cursor.moveToFirst()) {
do {
if (widgetId == cursor.getInt(1)) {
Log.i("City", cursor.getString(0));
return cursor.getString(0);
}
}
while (cursor.moveToNext());
}
}
cursor.close();
return null;
}
我在logcat中遇到Failed to read row 0, column 1 from a CursorWindow which has 1 rows, 1 columns.
我可以添加到此表(我可以确认,请查看下面的图片)
`Caused by: java.lang.IllegalStateException: Couldn't read row 0, col 1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.`
答案 0 :(得分:1)
你的问题是......你只选择一列...... KEY_CITY
SELECT" + KEY_CITY +"来自" + TABLE_WIDGET +&#34 ;;"
因此,您的查询结果只有一列
答案 1 :(得分:1)
如消息所示,光标有1行1列。列偏移从0开始。因此将列1指定为偏移将失败。
由于查询中只包含1列城市,因此widgetId == cursor.getInt(1)
不起作用,因为没有第1列,只有第0列。
或许更改查询以包含 widgetID 列,如下所示: -
Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_WIDGET + ";", null);
在这种情况下,表中的所有列都将包含在游标中。
您拥有的代码可以简化为: -
String rv;
if (while cursor.moveToNext) {
if (widgetId == cursor.getInt(1)) {
rv = cursor.getString(0);
cursor.close();
return rv;
}
cursor.close();
return null;
推理: -
从生成游标的SQLite方法返回时,Cursor永远不会为null,因此检查null是无用的。光标将存在,尽管它可能是空的。
所有光标移动????如果无法移动,方法将返回false。因此,如果光标无法移动到下一个并且不会输入while循环,while(cursor.moveToNext)
将返回false。这样可以处理空光标,因此不需要使用moveToFirst
进行检查。
完成后,您应始终隐藏光标。 return cursor.getString(0);
不会关闭光标。因此引入变量rv来保存从光标中提取的值,从而允许在返回之前关闭光标。
另一种方法是在查询中使用 WHERE 子句来选择相应的行。
这可能是
"SELECT * FROM " + TABLE_WIDGET + " WHERE " + KEY_ID + "=" + Integer.toString(widgetId);
最好在应用SQLite方便时使用它们,因此,许多人认为rawQuery
方法不是使用query
,而是更好的做法。这将构建SQL并执行它。
因此,您的getCity
方法可能是: -
public String getCity(long widgetId) {
String rv;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(
TABLE_WIDGET, //Table to extract cursor from
null, // Columns, null = all columns
KEY_ID + "=?", // Where clause, ? indicates an arg
new String[]{Long.toString(widgetId)}, //args
null,
null,
null);
if (cursor.moveToFirst()) {
rv = cursor.getString(cursor.getColumnIndex(KEY_CITY));
}
cursor.close();
return rv;
}
备注强>
理想情况下,您应该使用long
而不是int
来获取 id 列。这是因为rowid(您的id列为别名)可以达到高达9223372036854775807的值。SQLite Autoincrement 。
无需循环返回的游标,因为您知道它将返回空游标或带有1行的游标。
此处query更详细地解释了query
方法。有4种方法具有不同的签名。
args(第4个参数),一个String数组,将替换where子句(第3个参数)中的?' s。数组中元素的数量应与?的数量相匹配。它们按顺序使用,即第一个?将被第一个元素,第二个元素取代的值取代?来自第二个元素的值等。
答案 2 :(得分:1)
我运行了你的代码,问题在于
Cursor cursor = db.rawQuery("SELECT " + KEY_CITY + " FROM " + TABLE_WIDGET + ";", null);
您的表格有两列,您只需选择KEY_CITY列。使用以下代码更新它
Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_WIDGET + ";", null);