【问题标题】:SQLite IllegalStateException: where do I close the database?SQLite IllegalStateException:我在哪里关闭数据库?
【发布时间】:2012-02-28 09:22:23
【问题描述】:

在 Android 中创建和填充我的新 SQLiteDatabase 时,我遇到了两个相互矛盾的异常。简而言之,我的代码:

SQLiteOpenHelper 扩展类:

public void onCreate(SQLiteDatabase db) {
    db.execSQL(DB_TABLE_CREATE);
    loadLevelData(db); //puts data in the database
    //db.close(); <<< ?
}

在我的活动类中,我实例化了这个类(在 onCreate() 中),并调用 getWritableDatabase():

dbHelper = new DbOpenHelper(getApplicationContext());
database = dbHelper.getWritableDatabase();  

现在如果我在填充数据库后不调用db.close(),就像上面一样,我会得到

android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the   cursor or database object that was opened here  

但是,如果我关闭它,我会收到以下异常:

java.lang.IllegalStateException: database not open

在 getWritableDatabase() 上。

这真的让我很困惑,所以有人可以帮我解决问题吗?

【问题讨论】:

  • loadLevelData(db) 的放置代码;
  • 你能发布你制作的完整的数据库助手类吗?
  • 当你关闭数据库时,你需要在对数据库进行任何其他调用之前打开()。看来您没有调用 open()
  • 我相信 @Waqas 无关紧要,只有一些插入语句。并且 thinksteep,getWritableDatabase() 抛出第二个异常,所以我唯一可以放置 open() 的地方是紧跟在 close() 之后。

标签: android database sqlite exception illegalstateexception


【解决方案1】:

您不应该关闭DatabaseHelper 类中的数据库。但是,每次打开它时都需要关闭它,调用getWritableDatabase:

dbHelper = new DbOpenHelper(getApplicationContext());
database = dbHelper.getWritableDatabase();
//... do something with database
database.close();

【讨论】:

  • getWritableDatabase() 最初在助手中调用 onCreate(),然后我从那里修改数据库。如果我在 getWritabledatabase() 之后调用 close(),则异常已经被抛出。
  • onCreate 仅在您第一次尝试访问数据库时调用 - 它旨在创建表并在其中加载数据。 onCreate 是否被调用在SQLiteOpenHelper 的构造函数中确定,在onCreate 中传递的数据库对象在调用之前被初始化,在onCreate 返回之后在构造函数中关闭。这与您调用getWritableDatabase 的对象不同。您确实需要关闭的第二个。试试吧 - 在调用 getWritableDatabase 的方法结束时关闭它。
  • 嗯,它确实起作用了!我只是将 database.close() 放在 dbHelper.getWritableDatabase() 之后,它就起作用了。但这让我很困惑,因为异常是在 getWritableDatabase() 上抛出的,怎么能在它之后添加任何东西使它不给出异常?
  • 您没有完全正确地理解它。它说的是那里打开的数据库没有关闭。但是,异常本身发生在方法的末尾(或者更确切地说,当值被垃圾收集但未关闭时)。再次阅读异常...
【解决方案2】:

您在错误的时间关闭了数据库。

我通常这样保存数据库:

public class MyActivity extends Activity {
    SQLiteDatabase writeableDb;

    // ... 
    // Code
    // ...

    public void onStart(){
        super.onCreate(savedState);
        // Do stuff, get your helper, etc
        writeableDb = helper.getWriteableDatabase();
    }

    public void onStop(){
        writeableDb.close();
        super.onStop();
    }
}

或者,将使用该数据库连接的所有代码包装在 try/finally 块中

db = helper.getWriteableDatabase();
try { // ... do stuff ... }
finally { db.close(); }

注意:所有的打开/关闭都应该在与数据库一起使用的 Activity 中完成,而不是在 open 助手中完成。

【讨论】:

  • "所有的打开/关闭都应该在使用数据库的 Activity 中完成,而不是打开助手。" - 我不同意。我当前的应用程序有一个扩展 SQLiteOpenHelper 的类——它有超过 500 行代码和超过 20 种方法(大部分是公共的)。我的Actifity 类都没有与数据库本身有任何直接交互——一切都是通过调用助手的方法来完成的。
  • 您的解决方案并不比我的好,甚至可能更糟。现在,您已经将数据库的所有责任都放在了一个类中。因为我采取了一种非常懒惰的方法,所以我在活动中获得了一个数据库连接,并将它传递给一个为我完成所有获取的管理器。更好的解决方案是使用内容提供程序而不是直接使用数据库,它提供了我认为在 Android 上使用数据库的正确方法。可悲的是,我发现编写内容提供程序非常冗长。
  • “现在你已经把你的数据库的所有责任都丢给了一个类。”相反 - 我有一个类,它封装了我的其他代码(活动、服务等)所需的所有功能。他们都不需要知道任何关于数据库结构的事情,并且可以简单地请求他们需要的数据。如果数据库发生变化,我只需要修改助手中的代码,其他类照常进行。
猜你喜欢
  • 1970-01-01
  • 2017-02-25
  • 2011-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-05
相关资源
最近更新 更多