嘿。我正在尝试将光标对象返回到我的活动,它将在SimpleCursorAdapter中使用,但我有一个 close() was never explicity called
错误。我找不到任何解决此错误的方法,而且我将认为它是非解决方案错误,LOL。
和我一起思考。
错误说:
从未明确调用close() 数据库 '/data/data/com.example.myapp/databases/myDB.db'
也有警告:
在终结器中发布声明。 请确保您明确致电 光标上的close():SELECT * FROM contact_data ORDER BY duration desc
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的内部类(扩展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);
}
}
所以任何人都可以帮我解决这个问题?谢谢!
答案 0 :(得分:2)
不是在每个静态方法中创建新的OpenHelper,而是使用当前上下文将DataHandlerDB
实例化,并让类保存由getWritableDatabase
填充的变量。您正在创建由不同SQLiteOpenHelper
对象创建的多个光标对象,Android不喜欢这样做。
查看此信息以获取更多信息:http://www.ragtag.info/2011/feb/1/database-pitfalls/
这就像你在做什么一样......
public class DataHandlerDB{
public static SQLiteDatabase createDB(Context ctx) {
OpenHelper helper = new OpenHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase();
...
return db;
}
public static Cursor selectTopCalls(Context ctx) {
OpenHelper helper = new OpenHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase(); // error is here
...
return c;
}
}
这会导致多个并发SQLiteOpenHelper
个对象和多个SQLiteDatabase
对象以及您当前的锁定情况。
不是进行多次静态调用,而是创建一个DataHandler类,使用一致的上下文进行实例化,然后进行正常调用(而不是静态调用):
public class DataHandlerDB{
OpenHelper _helper;
SQLiteDatabse _db;
public DataHandlerDB( Context ctx ){
_helper = new OpenHelper(ctx);
_db = _helper.getWritableDatabase();
}
public SQLiteDatabase createDB() {
...
return db;
}
public Cursor selectTopCalls() {
...
return c;
}
}
public void setBasicContent() {
...
DataHandlerDB handler = new DataHandlerDB( this );
Cursor c = handler.selectValues(); //.selectTopCalls()?
...
}
创建此对象时,它会持续1 OpenHelper
和1 SQLiteDatabase
。这可以缓解SQLite在访问数据库之前需要关闭数据库的问题。
不要忘记在活动的onDestroy
方法中关闭数据库。