【发布时间】:2014-05-16 21:23:09
【问题描述】:
我一直在尝试解决有关我的应用程序和应用程序服务共享使用 SQLiteDatabase 的问题;即应用程序启动的服务。该服务每 30 秒唤醒一次并检查数据库,然后,就像所有好的进程一样,它在完成后关闭与数据库的连接。但是,当应用程序同时运行并尝试访问数据库时,应用程序会崩溃。 logcat 显示一条消息,警告我正在尝试重新打开已关闭的数据库连接,如下所示:
05-16 16:48:30.796: E/AndroidRuntime(10610): java.lang.IllegalStateException:尝试重新打开已经关闭的 对象:SQLiteDatabase:/data/data/com.example.myapp/databases/eRing
一项勤奋的故障排除工作表明,如果我取消了服务对数据库的关闭,一切都会好起来的,有点……如果我让服务周期足够长。最终,SQLiteConnectionPool 会醒来并说,
数据库的 SQLiteConnection 对象 '+data+data+com_example_myapp+databases+eRing' 被泄露了!请修复 您的申请以正确结束正在进行的交易并关闭 不再需要的数据库。
所以,我回到了绘图板上,查看了文档和教程。我注意到许多可用资源在不讨论 ContentProvider 的情况下几乎无法提及 SQLiteDatabases。但是,文档说,如果您打算从另一个应用程序访问数据库,则只需要 ContentProvider。以下是来自 Android 开发者网站的引述:
开始构建之前
在开始构建提供程序之前,请执行以下操作:
-
确定您是否需要内容提供商。如果要提供以下一项或多项,则需要构建内容提供程序 特点:
- 您想向其他应用程序提供复杂的数据或文件。
- 您希望允许用户将复杂数据从您的应用复制到其他应用中。
- 您想使用搜索框架提供自定义搜索建议。
如果使用完全在您自己的应用程序中,您不需要提供者来使用 SQLite 数据库。
我无法从这个文档中看出以下几点:对于 App 拥有 Service,并且 Activity 和 Service 都需要同时访问数据库的情况,这是否需要创建 ContentProvider?我很肯定我无意与其他任何东西或文档列出的任何其他场景共享此数据库。换句话说,Service 和 Activity 算不算两个“应用程序”? Android 基础知识将活动和服务称为“应用组件”,而不是单个“应用”。
请告诉我,是否值得付出所有努力来创建自定义 ContentProvider,并消除对数据库的直接访问(通过 SQLiteDBAdapters/Helpers)是否值得。
For Salem:下面是Activity和Service调用的close方法。
public class SettingsDbAdapter {
private static SQLiteDatabase mDb;
private DatabaseHelper mDbHelper;
public static class DatabaseHelper extends SQLiteOpenHelper {
//...
}
//...
public void close() {
Log.v("close()", "Close settingsdbadapter called");
mDbHelper.close();
}
}
//The following is the Services Open method:
public SettingsDbAdapter openReadable() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getReadableDatabase();
return this;
}
//The following is the Activities Open Method:
public SettingsDbAdapter open() throws SQLException {
mDb = mDbHelper.getWritableDatabase();
if (!mDb.isWriteAheadLoggingEnabled()) {
Log.v("SettingsDb","Trying to Enable Write Ahead Logging");
mDb.enableWriteAheadLogging();
}
return this;
}
【问题讨论】:
-
你能提供一个打开/关闭连接的代码的sn-p吗?
-
@Salem 请参阅上面的修订版。
-
尝试用
if (mDbHelper != null && mDbHelper.isOpen()) { mDbHelper.close(); }替换mDbHelper.close();。 -
@Salem,我假设您的意思是 mDb.isOpen?它产生相同的结果。