您的位置:首页 > 数据库

关闭ContentProvider中的数据库

2016-05-28 20:33 387 查看
这个星期,我一直在学习所有关于ContentProvider的的SQLiteOpenHelper的类来管理提供商内部的数据库的创建和升级。具体地讲,我一直在读通过记事本的例子来自SDK的samples目录。 现在,我可以看到,SQLiteOpenHelper的有一个close()方法。我知道,闲置数据库的开放是不好的做法,可以泄漏和诸如此类的东西(除非这是朝着正确的方向)。如果我的类中的活动
CodeGo.net,那么我会简单地调用close()方法中的onDestroy()方法,但据我所知,ContentProvider的不具有生命周期的活动做。记事本的代码似乎永远不会调用close(),所以我想它是由SQLiteOpenHelper的或其它的一块拼图处理,但我真的很想知道。我真的不示例代码多,要么... 问题总结:当我们要关闭数据库中的providers,如果在所有?
本文地址 :CodeGo.net/235632/ 
------------------------------------------------------------------------------------------------------------------------- 
1. 根据戴安Hackborn(android工程师),没有必要在一个内容提供者关闭数据库。
在创建它的宿主进程时,内容提供者创建,并 仍然围绕只要过程做,所以没有必要 关闭数据库-它会被关闭作为内核的一部分 清理过程中的资源,当进程被kill。 感谢@bigstones指出了这一点。 
2. 这个问题是有点老,但还是相当有关。请注意
CodeGo.net,如果你正在做的事情的“现代”的方式(例如使用LoaderManager和创造CursorLoaders查询在后台线程ContentProvider的),请确保你不调用db.close()在你的ContentProvider我得到各种有关CursorLoader / AsyncTaskLoader当它试图访问ContentProvider的在后台线程中,这是通过去除db.close()调用解决崩溃。 所以,如果你正在运行到崩溃,看起来像这样(果冻豆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(AsyncTask
b46f
Loader.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,并确保你没有关闭数据库过早。根据这一点,ContentProvider的会得到自动清理该过程时,反正杀了,所以你不需要提前关闭其数据库 这就是说,要确保你仍然正确: 关闭该从ContentProvider.query()返回的游标。 (CursorLoader /
LoaderManager这是否自动为你,但如果你正在做的LoaderManager外直接查询,或者你自定义的CursorLoader / AsyncTaskLoader子类,你必须确保你清理你的游标正常。) 您的ContentProvider以线程安全的方式。 (做到这一点最简单的方法就是确保你的数据库被包裹在一个synchronized块。) 
3. 香港专业教育学院遵循Mannaz的回答,只见那
SQLiteCursor(database,
driver, table, query);
构造函数被弃用。然后我发现
getDatabase()
它的方法,而不是
mDatabase
指针,并保持构造能力lag
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);
}
}


4. 如果你希望你的数据库自动关闭,您可以提供一个
CursorFactory
当打开它:

如果是用SQLiteOpenHelper,可以在queryWithFactory中添加,也可以在其构造函数中添加;

mContext.openOrCreateDatabase(DB_NAME, SQLiteDatabase.OPEN_READWRITE, new LeaklessCursorFactory());

下面是类:
public class LeaklessCursorFactory implements CursorFactory {
@Override
public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
String editTable, SQLiteQuery query) {
return new LeaklessCursor(db,masterQuery,editTable,query);
}
}

public class LeaklessCursor extends SQLiteCursor {
static final String TAG = "LeaklessCursor";
final SQLiteDatabase mDatabase;
public LeaklessCursor(SQLiteDatabase database, SQLiteCursorDriver driver, String table, SQLiteQuery query) {
super(database, driver, table, query);
mDatabase = database;
}
@Override
public void close() {
Log.d(TAG, "Closing LeaklessCursor: " + mDatabase.getPath());
super.close();
if (mDatabase != null) {
mDatabase.close();
}
}
}


5. 关闭它,当你用它做,最好是在finally块中,因此您可以确保它发生。我知道这听起来有点陈腐和现成的,袖口,但它是真的,我知道的唯一的答案。如果您打开数据库,并执行操作,关闭它,当你与该操作就完成了,除非你知道它会再次需要(在这种情况下,一定要关闭它一旦其不再需要的)的事实。 
6. 如果你的内容的活动中providers的话,我不相信,你必须维护内容提供者的连接。你可以只管理游标对象startManagingCursor。在活动中,你可以释放内容提供商。
(你可以假设该活动的生命周期是有限的重新加载,这样就足够了。(根据ATLEAST ;))
本文标题 :关闭数据库中的ContentProvider
本文地址 :CodeGo.net/235632/ 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: