本周,我学习了所有关于ContentProvider的知识,并使用SQLiteOpenHelper类在提供者中管理数据库的创建和升级。具体地说,我一直在通读sdk的samples目录中的NotePad示例。
现在,我可以看到SQLiteOpenHelper有一个close()方法。我知道让空闲数据库保持开放是一种糟糕的做法,可能会导致内存泄漏等问题(除非this讨论的方向是正确的)。如果我在活动中使用这个类,那么我会简单地在onDestroy()方法中调用close(),但据我所知,ContentProvider没有与活动相同的生命周期。NotePad的代码似乎从未调用过close(),所以我假设它是由SQLiteOpenHelper或其他部分处理的,但我真的很想确认一下。我也不是很信任示例代码……
问题摘要:我们应该在什么时候关闭提供者中的数据库?
发布于 2012-10-04 02:59:16
According to Dianne Hackborn (安卓框架工程师)不需要关闭内容提供商中的数据库。
内容提供者是在创建其宿主进程时创建的,并且只要该进程存在,它就会一直存在,因此不需要关闭数据库--它将作为内核的一部分在进程终止时被关闭,以清理进程的资源。
感谢@bigstones指出这一点。
发布于 2012-08-09 13:34:59
这个问题有点老了,但仍然很相关。请注意,如果您使用“现代”方式(例如,在后台线程中使用LoaderManager和创建CursorLoaders来查询ContentProvider ),请确保不要在ContentProvider实现中调用db.close()。当CursorLoader/AsyncTaskLoader试图在后台线程中访问ContentProvider时,我遇到了各种与CursorLoader/AsyncTaskLoader相关的崩溃,这些问题通过删除db.close()调用得到了解决。
因此,如果你遇到类似下面这样的崩溃(Jelly Bean 4.1.1):
Caused by: java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:677)
at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
at android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:143)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
at android.content.ContentResolver.query(ContentResolver.java:388)
at android.content.ContentResolver.query(ContentResolver.java:313)
at com.hindsightlabs.paprika.loaders.GroceryListLoader.loadInBackground(GroceryListLoader.java:147)
at com.hindsightlabs.paprika.loaders.GroceryListLoader.loadInBackground(GroceryListLoader.java:1)
at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:240)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:51)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:40)
at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:123)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
... 4 more或者这个(ICS 4.0.4):
Caused by: java.lang.IllegalStateException: database /data/data/com.hindsightlabs.paprika/databases/Paprika.db (conn# 0) already closed
at android.database.sqlite.SQLiteDatabase.verifyDbIsOpen(SQLiteDatabase.java:2215)
at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:436)
at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:422)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:79)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:164)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:156)
at android.content.ContentResolver.query(ContentResolver.java:318)
at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:49)
at android.support.v4.content.CursorLoader.loadInBackground(CursorLoader.java:35)
at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:240)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:51)
at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:40)
at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:123)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
... 4 more或者,如果您在LogCat中看到类似以下内容的错误消息:
Cursor: invalid statement in fillWindow()然后检查您的ContentProvider实现,并确保您没有过早关闭数据库。根据this的说法,当进程被杀死时,ContentProvider将被自动清理,所以你不需要提前关闭它的数据库。
也就是说,请确保您仍然是正确的:
发布于 2012-01-28 19:08:39
我看了Mannaz的回答,发现SQLiteCursor(database, driver, table, query);构造函数被弃用了。然后,我找到了getDatabase()方法,并用它代替了mDatabase指针;并保留了用于向后功能的构造函数
public class MyOpenHelper extends SQLiteOpenHelper {
public static final String TAG = "MyOpenHelper";
public static final String DB_NAME = "myopenhelper.db";
public static final int DB_VESRION = 1;
public MyOpenHelper(Context context) {
super(context, DB_NAME, new LeaklessCursorFactory(), DB_VESRION);
}
//...
}
public class LeaklessCursor extends SQLiteCursor {
static final String TAG = "LeaklessCursor";
public LeaklessCursor(SQLiteDatabase db, SQLiteCursorDriver driver,
String editTable, SQLiteQuery query) {
super(db, driver, editTable, query);
}
@Override
public void close() {
final SQLiteDatabase db = getDatabase();
super.close();
if (db != null) {
Log.d(TAG, "Closing LeaklessCursor: " + db.getPath());
db.close();
}
}
}
public class LeaklessCursorFactory implements CursorFactory {
@Override
public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
String editTable, SQLiteQuery query) {
return new LeaklessCursor(db,masterQuery,editTable,query);
}
}https://stackoverflow.com/questions/4547461
复制相似问题