在使用android时,我已经阅读了大量关于如何创建和使用数据库连接的博客和教程。虽然我有很多工作示例,但不同的实现会导致不同的问题。
示例,我使用数据源类Datasource
和数据库帮助程序类DBManagement
。
数据源
public class DataSource {
// Database fields
private SQLiteDatabase database;
private DBManagement dbHelper;
public SMSDataSource(Context context) {
dbHelper = new DBManagement(context);
}
public void open() throws SQLException {
if(database == null){
database = dbHelper.getWritableDatabase();
}
}
public Cursor exampleCursor(long constraint){
Cursor cur = database.query(DBManagement.TABLE_NAME,
new String[] {DBManagement.Column}, "constraint="+constraint, null, null, null, null);
return cur;
}
//.. other methods down here which do rawQuery, QueryBuilder, etc..
DBManagement
public class DBManagement extends SQLiteOpenHelper{
// .. table definitions and columns etc ..//
public DBManagement(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
在活动中的onCreate方法中,我将调用datasource.open()
并且SQL连接已打开。之后我会这样做:
DataSource datasource = new DataSource();
Cursor cursor = datasource.exampleCursor(1);
startManagingCursor(cursor);
如果我导航到新活动,则会收到以下错误:
06-27 21:59:14.812: E/Database(13396): close() was never explicitly called on database '/data/data/com.example.package/databases/db.db'
如果我将datasource.close();
添加到onCreate的末尾,则没有简单的游标适配器工作,或者如果在conextual菜单上执行操作,则会出现db未打开的错误。
处理上述问题的最佳方法是什么?
所以我做了以下操作,我仍然遇到了数据库问题:
@Override
public void onBackPressed() {
// do something on back.
//Log.i(getClass().toString(), "onBackPressed");
datasource.close();
finish();
return;
}
@Override
protected void onResume(){
super.onResume();
onCreate(null);
}
@Override
protected void onRestart(){
datasource = new DataSource(this);
datasource.open();
filters = datasource.getFilterCursor();
startManagingCursor(filters);
super.onRestart();
}
@Override
protected void onPause(){
//Log.i(getClass().toString(), "onPause");
((CursorAdapter) adapter).getCursor().close();
datasource.close();
super.onPause();
}
@Override
protected void onStop(){
//Log.i(getClass().toString(), "onStop");
datasource.close();
super.onStop();
}
我的 Datasource.java 类具有以下内容:
public Datasource(Context context){
dbHelper = new DBManagement(context);
}
public void open() throws SQLException {
if( database == null ){
database = dbHelper.getWritableDatabase();
}
}
public void close(){
if(dbHelper != null){
dbHelper.close();
}
}
答案 0 :(得分:5)
这实际上非常简单:
finally
)等。startManagingCursor()
close()
。当您的流程终止时,我将自动关闭。 此外:频繁的开启和关闭绝对是一个坏主意,因为它带来了相当多的开销。
使用装载机也是一种选择。您绝对不需要使用内容提供程序来使用加载程序,但它并不是那么简单。使用内容提供商涉及IPC,如果您不打算将数据导出到其他应用程序,则通常会出现过度杀伤。
答案 1 :(得分:4)
如果您在onCreate
中打开数据库,则可以关闭onDestroy
。
答案 2 :(得分:4)
问题的“理想”解决方案是转换为Content Providers
和Loaders
,并使用v4
兼容性库来实现向后兼容性。这样做,解决了这个问题,因为您不再关心打开和关闭数据库连接,并且您可以在后台而不是在UI线程上执行数据库操作。
由于startManagingCursor
已被弃用,因此它还可以为您的应用程序提供未来证明。它现在仍然可以使用,即使在4.1中,但它会在某些时候删除。
我还有另一篇关于使用内容提供商here的帖子,其中包含使用提供的其他原因,并提供了指向教程的链接。
我认为,谷歌在ContentProvider
方面的最大失败是,它无法提供一种简单直观的方法来构建它们。
答案 3 :(得分:2)
我会坚持在您从数据库中获取数据后立即关闭数据库连接。最好的方法是在onResume()
和onPause()
内再次打开和关闭。
答案 4 :(得分:2)
我记得有一个类似的问题,我只是在新的Activity中调用getWritableDatabase()而不关闭旧引用时重新创建错误。当我关闭SQLiteDatabase对象database
和 SQLiteOpenHelper对象dbHelper
时,我不再接收这些错误。
public void close() {
// Check against the database being created but not opened, close writable db
if(database != null) {
database.close();
database = null;
}
// In case someone calls DataSource.close() more than once...
if(dbHelper != null) {
dbHelper.close();
dbHelper = null;
}
}
希望有所帮助!