【问题标题】:Android database connections and cursors oh myAndroid 数据库连接和游标哦,我的
【发布时间】:2012-06-29 13:23:22
【问题描述】:

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

【问题讨论】:

  • 即使在 onPause、onStop 等关闭后仍然收到错误。
  • 请发布您的 DataSource.close() 代码。

标签: android database sqlite cursor


【解决方案1】:

这其实很简单:

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

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

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

【讨论】:

  • try/catch/finally 会直接进入 onCreate 吗?可以访问onCreate 中的数据库还是应该使用其他方法?
  • 尝试/最终去任何你使用光标的地方。通常不要从主线程访问数据库,你在哪里调用它并不重要。(只要你有一个有效的上下文来创建它)。
【解决方案2】:

如果您在onCreate 中打开数据库,那么您可以在onDestroy 中关闭。

【讨论】:

  • 我会说这不是一个好方法,因为如果您在进入另一个 Activity 之前没有完成 Activity,某些 Activity 也可能进入 Pause 状态。
  • 也许最好把它移到onResume/onPause。
  • 我用我的方法更新了这个问题。即使在暂停/停止/后按中关闭,我也会收到错误消息。
【解决方案3】:

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

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

我还有一篇关于使用 Content Providers here 的帖子,其中涉及使用提供的其他原因,并提供了教程链接。

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

【讨论】:

    【解决方案4】:

    我会坚持在您完成从数据库中提取数据后立即关闭数据库连接。最好还是在onResume()onPause() 内再次打开和关闭。

    【讨论】:

    • 现在,我应该打开,做我的事情,然后在 onResume 上再次关闭吗?还是只是打开和关闭?我是否还必须手动关闭我的列表适配器?在简历上,我需要重新创建它吗?
    • 当您从数据库中提取数据完成后,最好关闭您的数据库。
    • 在点击或操作的上下文或列表视图中,我是重新打开数据源还是运行光标重新查询?
    • 重新打开它,因为我猜不推荐使用 requery。
    【解决方案5】:

    我记得有一个类似的问题,每当我在新的 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;
        }
    }
    

    希望有帮助!

    【讨论】:

    • 我删除了所有 managecursor 调用并手动关闭它们,并在我的 dbhelper 上调用了 super.close,看起来问题就消失了。谢谢!
    • 对于我的每一项活动,我都在 onDestroy() 中清理了我的数据库......这很有效。
    猜你喜欢
    • 1970-01-01
    • 2017-06-17
    • 2019-07-14
    • 1970-01-01
    • 2011-05-13
    • 2018-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多