Android系统。空光标

时间:2013-06-11 09:11:50

标签: android sqlite android-sqlite android-cursor

我从设备复制数据库文件并在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()

2 个答案:

答案 0 :(得分:0)

我从未使用过

cursor.close();

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

对于光标加载器,我建议How to use loaders in Android

您还可以在github.com或code.google.com等搜索代码

希望这有帮助。

答案 1 :(得分:0)

我猜这是在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;
    }
}