SQLiteOpenHelper在query得到Cursor返回值异常问题探究

在使用SQLiteOpenHelper进行数据库查询时遇到Cursor返回异常问题。问题出现在SQLiteOpenHelper的查询函数中,涉及SQLiteCursor的创建及SQLiteQuery的构造过程。通过对SQLite连接、会话和查询准备过程的代码分析,揭示了查询语句与Cursor之间的关联,以及可能引发异常的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近开发的一个功能会用到SQLite,碰到一个问题,纠结了整整一个下午,终于找到原因,记录一下。

      功能很简单,创建了一个自定义的ListView,在每个ListView中都对应有一个Button,而该Button需要有个状态记录Button使用情况,比如Enable和Disable。顺利地创建了数据库和自定义ListView,在点击Button时,将ListView对应的信息通过setTag(key, value)传递,并在Button的onClick()中通过getTag(key)获得对应属性。以上步骤暂时都未碰到任何问题,接下来问题就来了。

      在SQLiteOpenHelper的继承类DataBaseProvider中,增加了一个查询数据记录的函数,代码如下:

	public Cursor query(String name) {
		SQLiteDatabase db = this.getReadableDatabase();
		String querySql = "select " + PKG_NAME + " , " + CMP_STATE + " from " + TABLE_APPS_NAME + " where " + 
						CMP_NAME + " = '" + compName + "'";
		
		Cursor cursor = db.rawQuery(querySql, null);
		return cursor;
	}
在反复跟踪这段代码时,发现得到的Cursor对象值总有问题,数据内容老是对应的database中table的Column名,未得到正确的database record。百思不得其解,对应地也查找了Android工程中其他数据库查询的操作,也大同小异,最后检查下来才发现,在rawQuery结束后,需要将cursor定位到record的起始位置,即需要再调用一下cursor.moveToFirst()。最新代码更新如下:

	public Cursor query(String name) {
		SQLiteDatabase db = this.getReadableDatabase();
		String querySql = "select " + PKG_NAME + " , " + CMP_STATE + " from " + TABLE_APPS_NAME + " where " + 
						CMP_NAME + " = '" + compName + "'";
		
		Cursor cursor = db.rawQuery(querySql, null);
		cursor.moveToFirst();
		return cursor;
	}
到这里,数据库功能上的问题已经解决了,但是作为有专研精神的码农怎么能放过Discovery的好机会呢?那么我们从SQLiteDatabase的rawQuery接口开始分析,码农比较习惯以文件名来划分步骤:

1、SQLiteDatabase.java

    public Cursor rawQuery(String sql, String[] selectionArgs,
            CancellationSignal cancellationSignal) {
        return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
    }

显然,rawQuery(......)又调用了rawQueryWithFactory(......),函数如下:

    public Cursor rawQueryWithFactory(
            CursorFactory cursorFactory, String sql, String[] selectionArgs,
            String editTable, CancellationSignal cancellationSignal) {
        acquireReference();
        try {
            SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
                    cancellationSignal);
            return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
                    selectionArgs);
        } finally {
            releaseReference();
        }
    }
从代码看,是先创建了一个SQLiteDirectCursorDriver实例,并由该实例driver来执行query(...)。

2、SQLiteDirectCursorDriver.java

    public Cursor query(CursorFactory factory, String[] selectionArgs) {
        final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
        final Cursor cursor;
// 位置: java/com/example/todoapp/DatabaseHelper.java public class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "todo.db"; private static final int DATABASE_VERSION = 1; private static final String TABLE_TASKS = "tasks"; private static final String COLUMN_ID = "id"; private static final String COLUMN_TITLE = "title"; // 其他列定义... public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { String CREATE_TABLE = "CREATE TABLE " + TABLE_TASKS + "(" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + COLUMN_TITLE + " TEXT," + "description TEXT," + "is_completed INTEGER DEFAULT 0," + "category TEXT," + "timestamp INTEGER)"; db.execSQL(CREATE_TABLE); } // 添加任务 public void addTask(Task task) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(COLUMN_TITLE, task.getTitle()); values.put("description", task.getDescription()); values.put("category", task.getCategory()); values.put("timestamp", task.getTimestamp()); db.insert(TABLE_TASKS, null, values); db.close(); } // 获取所有任务 public List<Task> getAllTasks() { List<Task> taskList = new ArrayList<>(); String selectQuery = "SELECT * FROM " + TABLE_TASKS; SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(selectQuery, null); if (cursor.moveToFirst()) { do { Task task = new Task( cursor.getString(1), cursor.getString(2), cursor.getString(4) ); task.setId(cursor.getInt(0)); task.setCompleted(cursor.getInt(3) == 1); taskList.add(task); } while (cursor.moveToNext()); } cursor.close(); return taskList; } // 更新任务状态/删除任务等方法(此处省略) } 刚才就是这段代码报了上面的错误,大面积的No candidates found for method call task.getTitle().报错或No candidates found for method call cursor.getString(2).这个报错,请帮我检查并尝试在不改变源程序的情况下修改
06-18
检查以下代码里的问题;package com.example.myapplication; import android.annotation.SuppressLint; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; public class PersonDBHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "Person.db"; private static final int DATABASE_VERSION = 1; public static final String TABLE_PERSON = "person"; public static final String COLUMN_ID = "id"; public static final String COLUMN_NAME = "name"; public static final String COLUMN_NUMBER = "number"; public static final String COLUMN_ISSTAR = "isstar"; private static final String CREATE_TABLE = "CREATE TABLE " + TABLE_PERSON + " (" + COLUMN_ID + " Text, " + COLUMN_NAME + " TEXT, " + COLUMN_NUMBER + " TEXT, " + COLUMN_ISSTAR + " BOOLEANn )"; public PersonDBHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TABLE_PERSON); onCreate(db); } public String insertPerson(Person person){ SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(COLUMN_NAME, person.getName()); values.put(COLUMN_NUMBER, person.getNumber()); values.put(COLUMN_ID, person.getId()); values.put(COLUMN_ISSTAR, person.isStar()); db.close(); return person.getName(); } @SuppressLint("Range") public List<Person> getAllPersons() { List<Person> persons = new ArrayList<>(); SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.query(TABLE_PERSON, null, null, null, null, null, null); if (cursor.moveToFirst()) { do { @SuppressLint("Range") Person person = new Person( cursor.getString(cursor.getColumnIndex(COLUMN_NAME)), cursor.getString(cursor.getColumnIndex(COLUMN_NUMBER)), cursor.getString(cursor.getColumnIndex(COLUMN_ID)), "true".equals(cursor.getString(cursor.getColumnIndex(COLUMN_ID))) ); persons.add(person); } while (cursor.moveToNext()); } cursor.close(); return persons; } }
最新发布
07-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值