如何修复“请确保在光标上显式调用 close()”?
我正在构建一个具有以下代码的 Activity 的 Android 应用程序:
public class SavedSalesActivity extends Activity {
protected ListView mSalesList;
protected Cursor mSalesCursor;
protected SalesCursorAdapter mSalesAdapter;
protected SalesDbAdapter mDb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sales_list);
mDb = new SalesDbAdapter(this);
mDb.open();
mSalesCursor = mDb.getSaved();
startManagingCursor(mSalesCursor);
mSalesAdapter = new SalesCursorAdapter(this, R.layout.sales_list_item, mSalesCursor,
new String[0], new int[0]);
mSalesList = (ListView)findViewById(R.id.sales_listview);
mSalesList.setAdapter(mSalesAdapter);
mSalesList.setEmptyView(findViewById(android.R.id.empty));
mSalesList.setOnItemClickListener(new OnItemClickListener() {...});
}
@Override
protected void onStart() {
Log.v(TAG, "Starting SavedSalesActivity");
mDb.open();
mSalesCursor = mDb.getSaved();
startManagingCursor(mSalesCursor);
super.onStart();
}
@Override
protected void onStop() {
Log.v(TAG, "Stopping SavedSalesActivity");
mSalesCursor.close();
mDb.close();
super.onStop();
}
}
根据我的理解,这应该足以正确关闭我的所有资源,但是如果我打开此 Activity 并使用 Android 设备后退按钮退出它,我会得到经过一段短(可变)时间后,Logcat 中会出现此情况。
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): Releasing statement in a finalizer. Please ensure that you explicitly call close() on your cursor: SELECT * FROM sales ORDER BY featured DESC
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:62)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:80)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:46)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:42)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1345)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1229)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1184)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1264)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at com.maps.app.classifiedconcepts.sale.SalesDbAdapter.getSaved(SalesDbAdapter.java:149)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at com.maps.app.classifiedconcepts.sale.SavedSalesActivity.onCreate(SavedSalesActivity.java:113)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.os.Handler.dispatchMessage(Handler.java:99)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.os.Looper.loop(Looper.java:123)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread.main(ActivityThread.java:4627)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at java.lang.reflect.Method.invokeNative(Native Method)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at java.lang.reflect.Method.invoke(Method.java:521)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at dalvik.system.NativeStart.main(Native Method)
03-08 19:33:58.503: ERROR/Database(5169): close() was never explicitly called on database '/data/data/com.maps.app.classifiedconcepts/databases/classified_concepts'
03-08 19:33:58.503: ERROR/Database(5169): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1810)
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:817)
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:851)
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:844)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:540)
03-08 19:33:58.503: ERROR/Database(5169): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:203)
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:112)
03-08 19:33:58.503: ERROR/Database(5169): at com.maps.app.classifiedconcepts.sale.SalesDbAdapter.open(SalesDbAdapter.java:163)
03-08 19:33:58.503: ERROR/Database(5169): at com.maps.app.classifiedconcepts.sale.SavedSalesActivity.onCreate(SavedSalesActivity.java:112)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
03-08 19:33:58.503: ERROR/Database(5169): at android.os.Handler.dispatchMessage(Handler.java:99)
03-08 19:33:58.503: ERROR/Database(5169): at android.os.Looper.loop(Looper.java:123)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread.main(ActivityThread.java:4627)
03-08 19:33:58.503: ERROR/Database(5169): at java.lang.reflect.Method.invokeNative(Native Method)
03-08 19:33:58.503: ERROR/Database(5169): at java.lang.reflect.Method.invoke(Method.java:521)
03-08 19:33:58.503: ERROR/Database(5169): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
03-08 19:33:58.503: ERROR/Database(5169): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
03-08 19:33:58.503: ERROR/Database(5169): at dalvik.system.NativeStart.main(Native Method)
mSalesCursor = mDb.getSaved(); 行在我的 SalesDbAdapter 中调用以下代码:
public Cursor getSaved() {
return mDb.query(TABLE_NAME, null, null, null, null, null, KEY_FEATURED + " DESC");
}
我做错了什么?为什么我会遇到这些异常?我特别困惑,因为我认为在初始化 mSalesCursor 之后立即调用 startManagingCursor(mSalesCursor) 将使我无需在任何活动生命周期方法中关闭游标。
I'm building an Android application with an activity that has the following code:
public class SavedSalesActivity extends Activity {
protected ListView mSalesList;
protected Cursor mSalesCursor;
protected SalesCursorAdapter mSalesAdapter;
protected SalesDbAdapter mDb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sales_list);
mDb = new SalesDbAdapter(this);
mDb.open();
mSalesCursor = mDb.getSaved();
startManagingCursor(mSalesCursor);
mSalesAdapter = new SalesCursorAdapter(this, R.layout.sales_list_item, mSalesCursor,
new String[0], new int[0]);
mSalesList = (ListView)findViewById(R.id.sales_listview);
mSalesList.setAdapter(mSalesAdapter);
mSalesList.setEmptyView(findViewById(android.R.id.empty));
mSalesList.setOnItemClickListener(new OnItemClickListener() {...});
}
@Override
protected void onStart() {
Log.v(TAG, "Starting SavedSalesActivity");
mDb.open();
mSalesCursor = mDb.getSaved();
startManagingCursor(mSalesCursor);
super.onStart();
}
@Override
protected void onStop() {
Log.v(TAG, "Stopping SavedSalesActivity");
mSalesCursor.close();
mDb.close();
super.onStop();
}
}
According to my understanding this should be more than sufficient to properly close all my resources, however if I open this activity and exit it with the Android device back button I get this in Logcat after a short (variable) period of time.
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): Releasing statement in a finalizer. Please ensure that you explicitly call close() on your cursor: SELECT * FROM sales ORDER BY featured DESC
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:62)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:80)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:46)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:42)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1345)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java:1229)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1184)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.database.sqlite.SQLiteDatabase.query(SQLiteDatabase.java:1264)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at com.maps.app.classifiedconcepts.sale.SalesDbAdapter.getSaved(SalesDbAdapter.java:149)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at com.maps.app.classifiedconcepts.sale.SavedSalesActivity.onCreate(SavedSalesActivity.java:113)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.os.Handler.dispatchMessage(Handler.java:99)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.os.Looper.loop(Looper.java:123)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at android.app.ActivityThread.main(ActivityThread.java:4627)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at java.lang.reflect.Method.invokeNative(Native Method)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at java.lang.reflect.Method.invoke(Method.java:521)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
03-08 19:33:58.492: WARN/SQLiteCompiledSql(5169): at dalvik.system.NativeStart.main(Native Method)
03-08 19:33:58.503: ERROR/Database(5169): close() was never explicitly called on database '/data/data/com.maps.app.classifiedconcepts/databases/classified_concepts'
03-08 19:33:58.503: ERROR/Database(5169): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1810)
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:817)
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:851)
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:844)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:540)
03-08 19:33:58.503: ERROR/Database(5169): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:203)
03-08 19:33:58.503: ERROR/Database(5169): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:112)
03-08 19:33:58.503: ERROR/Database(5169): at com.maps.app.classifiedconcepts.sale.SalesDbAdapter.open(SalesDbAdapter.java:163)
03-08 19:33:58.503: ERROR/Database(5169): at com.maps.app.classifiedconcepts.sale.SavedSalesActivity.onCreate(SavedSalesActivity.java:112)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
03-08 19:33:58.503: ERROR/Database(5169): at android.os.Handler.dispatchMessage(Handler.java:99)
03-08 19:33:58.503: ERROR/Database(5169): at android.os.Looper.loop(Looper.java:123)
03-08 19:33:58.503: ERROR/Database(5169): at android.app.ActivityThread.main(ActivityThread.java:4627)
03-08 19:33:58.503: ERROR/Database(5169): at java.lang.reflect.Method.invokeNative(Native Method)
03-08 19:33:58.503: ERROR/Database(5169): at java.lang.reflect.Method.invoke(Method.java:521)
03-08 19:33:58.503: ERROR/Database(5169): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
03-08 19:33:58.503: ERROR/Database(5169): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
03-08 19:33:58.503: ERROR/Database(5169): at dalvik.system.NativeStart.main(Native Method)
The line mSalesCursor = mDb.getSaved(); calls the following code in my SalesDbAdapter:
public Cursor getSaved() {
return mDb.query(TABLE_NAME, null, null, null, null, null, KEY_FEATURED + " DESC");
}
What am I doing wrong? Why am I getting these exceptions? I'm especially puzzled because I thought that calling startManagingCursor(mSalesCursor) right after initializing mSalesCursor would save me from the need to close the Cursor in any of the Activity Lifecycle methods.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于其他查看此答案的人,我总是用 try/catch/finally 语句包装我的游标用法。这提供了无论发生什么情况游标都会关闭的确定性。
我经常使用它,甚至制作了一个 Eclipse 模板。
例子:
For other people looking at this answer, I always wrap my Cursor usage with try/catch/finally statements. This provides certainty that the cursor gets closed, regardless of what happens.
I use this so often that I've even made an Eclipse template.
example:
对于这些类型,您应该重写
onResume()
和onPause()
而不是onStart()
和onStop()
的事情。查看活动生命周期文档。You should override
onResume()
andonPause()
instead ofonStart()
andonStop()
for these kinds of things. Check out the Activity Lifecycle documentation.考虑调用 startManagingCursor() 。
Consider calling startManagingCursor().