0

我从设备复制数据库文件并在 SQLite 客户端中打开。SQLite 客户端中的相同查询按预期返回结果,但 Android有时返回空游标。我无法解释为什么有时游标会返回 0 行。SQLiteDatabase 对象总是按应用程序打开,因为每个任务对数据库有很多请求。

SQLiteDatabase database = this.getReadableDatabase();
try {
    Cursor cursor = database.rawQuery(query, null);
    try {
        Log.d("Cursor rows count size: ", String.valueOf(cursor.getCount()));
        if(cursor.moveToFirst()) {
            do {                
                Long a= cursor.getLong(cursor.getColumnIndex(TableA.a));
                String b = String.valueOf(cursor.getInt(cursor.getColumnIndex(TableA.b)));
                String c = cursor.getString(cursor.getColumnIndex(TableA.c));
                String d = cursor.getString(cursor.getColumnIndex(TableA.d));
                String e = cursor.getString(cursor.getColumnIndex(TableA.e));

                Object record = new Object (a, b, c, d, e);             
                list.add(record );              
            } while (cursor.moveToNext());
        } 
    } finally {
        cursor.close();
    }           
} finally {

}

更新

SQL查询(更改了列名和表名,重命名没有影响):

SELECT
    a ,
    b ,
    c ,
    d ,
    e
FROM TableA
    INNER JOIN TableB ON(TableB._id=TableA.y_id)
    LEFT JOIN TableC ON(TableC._id=TableA.x_id)
WHERE active=1 AND xxx>1370090365365 AND xxx<1370867965365
ORDER BY TableA.xxx DESC

就像我说的:这个查询按我的预期运行,并在桌面 SQLite 客户端中返回结果。

更新

此外,尽管所有 Cursor 和 SQLiteDatabase 对象都被try...finally包装并关闭,但我收到了这种警告。

W/CursorWrapperInner(10374): Cursor finalized without prior close()
4

2 回答 2

0

我猜这是在 a 内部SQLiteOpenHelper,我建议为了避免锁定,是使用getWritableDatabase而不是getReadableDatabase,而不是在活动/对象期间维护数据库对象/无论是有一些方法来处理它.

例如:

private SQLiteDatabase mWritable;

public SQLiteDatabase getDatabase(){
    if(mWritable == null)
        mWritable = this.getWritableDatabase();
    if(mWritable.isOpen())
        return mWritable;
    else
        mWritable = this.getWritableDatabase();
    return mWritable;
}

public void start(){
    mWritable = getDatabase();
}

public void stop(){
    if(mWritable != null)
        if(mWritable.isOpen())
            if(!mWritable.inTransaction())
                mWritable.close();
}

public void end(){
    if(mWritable == null)
        return;
    if(mWritable.isOpen()){
        if(mWritable.inTransaction())
            mWritable.endTransaction();
        mWritable.close();
    }
}

这可以负责管理数据库。我还建议向您的助手添加一些其他方法,这可能会有所帮助...

public Cursor Query(String query, String ... params){
    this.startReading();
    Cursor c = mWritable.rawQuery(query, params);
    return c;
}

public String GetScalar(String query, String ... params){
    String res = null;
    this.startReading();
    Cursor c;
    try {
        c = Query(query, params);
        if(c.moveToFirst()){
            if(!c.isNull(0)){
                res = c.getString(0);
            }
        }
        c.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    this.stopReading();
    return res;
}

public String GetScalar(String query){
    return GetScalar(query, new String[0]);
}

public String[] GetColumn(String query, String ... params){
    List<String> list = new ArrayList<String>();
    this.startReading();
    Cursor c;
    try {
        c = Query(query, params);
        while(c.moveToNext()){
            if(!c.isNull(0)){
                list.add(c.getString(0));
            }
        }
        c.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    this.stopReading();
    return list.toArray(new String[0]);
}

public String[] GetColumn(String query){
    return GetColumn(query, new String[0]);
}

我建议您从设备复制数据库,或者通过使用应用程序复制数据库,或者如果您的应用程序浏览data/data/<your package name>/databases/<database name>并使用 SQLiteDatabaseBrowser ( http://sourceforge.net/projects/sqlitebrowser/ ) 通过它并运行使用此查询并检查结果。

如果您需要复制数据库,因为您没有 root 访问权限,您可以使用以下内容:

public static boolean CopyDatabase(DbHelper dbHelper) {
    try {
        File sd = Environment.getExternalStorageDirectory();
        File data = Environment.getDataDirectory();

        if (sd.canWrite()) {
            String currentDBPath = "//data//" + dbHelper.getPackageName()
                    + "//databases//" + DbHelper.DATABASE_NAME;
            String backupDBPath = "/Databases/";

            Log.d("Path", sd.getPath() + backupDBPath);
            File backupDir = new File(sd.getPath() + "/" + backupDBPath);
            File currentDB = new File(data, currentDBPath);

            if (!backupDir.exists()) {
                if (!backupDir.mkdirs()) {
                    Log.d("Path", "Can not make directory");
                }
            } else {
                Log.d("Path", "Directory exists");
            }

            File backupDB = new File(backupDir, DbHelper.DATABASE_NAME);

            FileInputStream fis = new FileInputStream(currentDB);
            FileOutputStream fos = new FileOutputStream(backupDB);
            FileChannel src = fis.getChannel();
            FileChannel dst = fos.getChannel();
            dst.transferFrom(src, 0, src.size());
            src.close();
            dst.close();
            fis.close();
            fos.close();
            return true;
        }
        Log.e("DbCopy", "Can not write to sdcard");
        return false;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}
于 2013-07-31T03:51:29.443 回答
0

我从来没有使用过

cursor.close();

这就带来了如何管理光标的问题,这实际上取决于您的应用程序的目标版本。对于 Honeycomb 及之后的版本,我会查看“光标加载器”,在此之前使用“startManagingCursor”,但我相信它会推荐给用户光标加载器,这将消除您关闭光标的需要。由于游标是异步类型的任务,您可以在游标返回任何结果之前关闭游标。

对于光标加载器,我建议如何在 Android 中使用加载器

也可以在 github.com 或 code.google.com 等搜索代码。

希望这可以帮助。

于 2013-07-31T03:18:30.590 回答