3

我已经阅读了大量关于如何在使用 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.. 

数据库管理

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 的末尾,那么简单的光标适配器都不起作用,或者如果在上下文菜单上执行操作,我会收到数据库未打开的错误。

处理上述问题的最佳方法是什么?

所以我做了以下事情,但我仍然遇到数据库问题:

@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();
    }
}
4

5 回答 5

5

这实际上非常简单:

  • 完成后显式关闭所有游标(使用finally)等。
  • 不要使用startManagingCursor()
  • 使您的数据库包装器/帮助器/管理器/任何类成为单例
  • 不要显式调用close()数据库助手。当您的进程终止时,我将自动关闭。

另外:频繁打开和关闭绝对是一个坏主意,因为它会带来很多开销。

使用装载机也是一种选择。您绝对不需要使用内容提供程序来使用加载程序,但是它并不像它可能的那么简单。使用内容提供程序涉及 IPC,如果您不打算将数据导出到其他应用程序,这通常是矫枉过正的。

于 2012-07-19T04:03:30.163 回答
4

如果您在其中打开数据库,onCreate则可以在onDestroy.

于 2012-06-29T13:24:25.893 回答
4

您的问题的“理想”解决方案是转换到Content Providersand Loaders,并使用v4兼容性库来实现向后兼容性。这样做可以解决这个问题,因为您不再关心打开和关闭数据库连接,并且您可以在后台而不是在 UI 线程上执行数据库操作。

它还可以为您的应用程序提供未来证明,因为startManagingCursor它已被弃用。它现在仍然可以使用,即使在 4.1 中,但它会在某个时候被删除。

我在这里有另一篇关于使用内容提供者的帖子,其中涉及使用提供的其他原因,并提供了教程的链接。

我认为,对于 Google 而言,最大的失败ContentProvider在于它没有提供一种简单直观的方式来构建它们。

于 2012-06-29T13:36:53.860 回答
2

我会坚持在您完成从数据库中获取数据后立即关闭数据库连接。最好的办法是在里面再次打开和onResume()关闭onPause()

于 2012-06-29T13:31:19.877 回答
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;
    }
}

希望有帮助!

于 2012-07-21T17:10:34.720 回答