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