How do I fix "Please ensure that you explicitly call close() on your cursor"?
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.
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:
void foo() {
Cursor c = null;
try {
c = db.get_somthing();
do_something©;
}
catch (Exception e) {
print_err_msg(e);
}
finally {
if (c != null) {
c.close();
c = null;
}
}
}
You should override onResume()
and onPause()
instead of onStart()
and onStop()
for these kinds of things. Check out the Activity Lifecycle documentation.
Consider calling startManagingCursor().
精彩评论