无法返回 Cursor 对象 - close() 从未明确调用错误
嘿。我正在尝试将光标对象返回到我的活动,它将在 SimpleCursorAdapter 中使用,但我遇到 close() was never Explyy Called
错误。我找不到此错误的任何解决方案,并且我认为这是一个非解决方案错误,哈哈。
和我一起思考。
错误说:
close() 从未被显式调用过 数据库 '/data/data/com.example.myapp/databases/myDB.db'
并且也有一个警告:
在终结器中释放语句。 请确保您明确致电 close() 光标处:SELECT * FROM contact_data ORDER BY 持续时间说明
android.database.sqlite.DatabaseObjectNotClosedException: 应用程序未关闭此处打开的游标或数据库对象
错误出在该方法中,即在类 DataHandlerDB(处理数据库)中
public static Cursor selectTopCalls(Context ctx) {
OpenHelper helper = new OpenHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase(); // error is here
Cursor cursor = db.query(TABLE_NAME_2, null, null, null, null, null,
"duration desc");
return cursor;
}
该方法通过以下方法在我的活动中使用:
public void setBasicContent() {
listview = (ListView) findViewById(R.id.list_view);
Log.i(LOG_TAG, "listview " + listview);
Cursor c = DataHandlerDB.selectTopCalls(this); // here I use the method
startManagingCursor(c);
adapter = new SimpleCursorAdapter(this, R.layout.list_item, c, new String[] {
DataHandlerDB.CONTACT_NAME_COL,
DataHandlerDB.CONTACT_NUMBER_COL,
DataHandlerDB.CONTACT_DURATION_COL,
DataHandlerDB.CONTACT_DATE_COL }, new int[] {
R.id.contact_name, R.id.phone_number, R.id.duration, R.id.date });
Log.i(LOG_TAG, "before setAdapter");
Toast.makeText(this, "Before setAdapter", Toast.LENGTH_SHORT).show();
listview.setAdapter(adapter);
}
我尝试关闭游标和此方法内的数据库,但是当我这样做时,错误未修复,并且它不打印我的列表。
我尝试在 selectValues() 方法上关闭它,但是当这样做时,它说尝试重新打开已经关闭的光标(类似的)。
我还尝试在 onDestroy()、onStop() 中关闭游标和数据库,但没有成功。
这就是为什么我认为没有解决方案。我该怎么办?
类 DataHandlerDB.java 有一个 createDB() 方法:
public static SQLiteDatabase createDB(Context ctx) {
OpenHelper helper = new OpenHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase();
helper.onOpen(db);
db.close();
return db;
}
和一个名为 OpenHelper(extends SQLiteOpenHelper) 的内部类
public static class OpenHelper extends SQLiteOpenHelper {
private final Context mContext;
OpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
String[] sql = mContext.getString(
R.string.MyString_OnCreate).split("\n");
db.beginTransaction();
try {
execMultipleSQL(db, sql);
db.setTransactionSuccessful();
} catch (SQLException e) {
Log.e("Error creating tables and debug data", e.toString());
throw e;
} finally {
db.endTransaction();
}
}
private void execMultipleSQL(SQLiteDatabase db, String[] sql) {
for (String s : sql) {
if (s.trim().length() > 0) {
db.execSQL(s);
}
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
/*
* Log.w("My Database",
* "Upgrading database, this will drop tables and recreate.");
* db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db);
*/
}
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}
}
所以任何人都可以帮助我解决这个问题?谢谢!
Hey. I'm trying to return a cursor object to my activity where its gonna be used in a SimpleCursorAdapter, but Im having a close() was never explicity called
error. I cant find any solution for this error, and I'm about to think that its a non-solution error, LOL.
Think with me.
The error says:
close() was never explicitly called on
database
'/data/data/com.example.myapp/databases/myDB.db'
And has a warning too:
Releasing statement in a finalizer.
Please ensure that you explicitly call
close() on your cursor: SELECT * FROM
contact_data ORDER BY duration descandroid.database.sqlite.DatabaseObjectNotClosedException:
Application did not close the cursor or database object that was opened here
The error is in this method, that is in the class DataHandlerDB (deals with database)
public static Cursor selectTopCalls(Context ctx) {
OpenHelper helper = new OpenHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase(); // error is here
Cursor cursor = db.query(TABLE_NAME_2, null, null, null, null, null,
"duration desc");
return cursor;
}
This method is used on my activity, by this following method:
public void setBasicContent() {
listview = (ListView) findViewById(R.id.list_view);
Log.i(LOG_TAG, "listview " + listview);
Cursor c = DataHandlerDB.selectTopCalls(this); // here I use the method
startManagingCursor(c);
adapter = new SimpleCursorAdapter(this, R.layout.list_item, c, new String[] {
DataHandlerDB.CONTACT_NAME_COL,
DataHandlerDB.CONTACT_NUMBER_COL,
DataHandlerDB.CONTACT_DURATION_COL,
DataHandlerDB.CONTACT_DATE_COL }, new int[] {
R.id.contact_name, R.id.phone_number, R.id.duration, R.id.date });
Log.i(LOG_TAG, "before setAdapter");
Toast.makeText(this, "Before setAdapter", Toast.LENGTH_SHORT).show();
listview.setAdapter(adapter);
}
I try to close the cursor and database inside this method, but when I do that, the error is not fixed, and it doesnt print my list.
I tried to close it on the selectValues() method, but when doing that, it says, trying to re-open cursor already closed (something like that).
I also tried to close the cursor and database in onDestroy(), onStop() but it didnt worked.
Thats why I thought there were no soluytion for that. What am I supose to do?
The class DataHandlerDB.java, has a createDB() method:
public static SQLiteDatabase createDB(Context ctx) {
OpenHelper helper = new OpenHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase();
helper.onOpen(db);
db.close();
return db;
}
And an Inner Class called OpenHelper(extends SQLiteOpenHelper)
public static class OpenHelper extends SQLiteOpenHelper {
private final Context mContext;
OpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
String[] sql = mContext.getString(
R.string.MyString_OnCreate).split("\n");
db.beginTransaction();
try {
execMultipleSQL(db, sql);
db.setTransactionSuccessful();
} catch (SQLException e) {
Log.e("Error creating tables and debug data", e.toString());
throw e;
} finally {
db.endTransaction();
}
}
private void execMultipleSQL(SQLiteDatabase db, String[] sql) {
for (String s : sql) {
if (s.trim().length() > 0) {
db.execSQL(s);
}
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
/*
* Log.w("My Database",
* "Upgrading database, this will drop tables and recreate.");
* db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db);
*/
}
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}
}
So anyone can help me to fix this problem?? Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不要在每个静态方法中创建新的 OpenHelper,而是使用当前上下文实例化
DataHandlerDB
并让该类保存由getWritableDatabase
填充的变量。您正在创建由不同SQLiteOpenHelper
对象创建的多个游标对象,而 Android 不喜欢这样做。查看此以获取更多信息:http://www.ragtag.info/2011 /feb/1/database-pitfalls/
在我看来,您正在做的事情是这样的...
这会导致多个并发
SQLiteOpenHelper
对象和多个SQLiteDatabase 对象以及您当前拥有的锁定情况。
不要执行多个静态调用,而是创建一个使用一致上下文实例化的 DataHandler 类,然后进行正常调用(而不是静态调用):
当您创建此对象时,它将保留 1
OpenHelper
和 1SQLite数据库
。这应该可以缓解 SQLite 在访问数据库之前需要关闭数据库的问题。不要忘记在 Activity 的
onDestroy
方法中关闭数据库。Instead of creating a new OpenHelper in each of your static methods, instantialize your
DataHandlerDB
with the current context and have the class hold a variable populated bygetWritableDatabase
. You are creating multiple cursor objects created by differentSQLiteOpenHelper
objects and Android doesn't like doing this.Check this out for additional info: http://www.ragtag.info/2011/feb/1/database-pitfalls/
Here's how it looks to me like you're doing things...
This results in multiple concurrent
SQLiteOpenHelper
objects and multipleSQLiteDatabase
objects and the locking situation you currently have.Instead of doing multiple Static calls, make a DataHandler class that you instantialize with the consistent context and then make normal calls (instead of static ones):
When you create this object, it will persist 1
OpenHelper
and 1SQLiteDatabase
. This should alleviate the problems with SQLite wanting the database closed before it can access it.Don't forget to close the DB in the
onDestroy
method of your activity.