为什么我得到关于重新打开已经关闭的数据库的IllegalStateException?

时间:2016-05-23 19:20:38

标签: android sqlite sqliteopenhelper

最近,我在我的应用程序中使用的SQLite数据库遇到了一些奇怪的行为。它主要是一个IllegalStateException,说:IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:

下面是抛出错误的方法的简化版本。下面是日志。

我对SQLiteDatabases并不熟悉,所以我不确定它是否适合我。此外,我在网上找到的解决方案似乎都不适用于我的案例。

所以基本上,导致这种情况的原因以及如何解决?

修改

5月24日

我一直在进行一些测试,结果db.isOpen()falseif else下面ContentValues values = new ContentValues();返回db.isReadOnly()。在代码中的任何其他位置调用它时,它返回true。 奇怪的是,private void updateAppUsages(@Nullable ArrayList<String> name, @Nullable ArrayList<Action> action, @Nullable ArrayList<Integer> changeAmount) { SQLiteDatabase db; db = getWritableDatabase(); String query = "SELECT * FROM " + TABLE_AppTable2 + " WHERE 1"; if (name.size() != action.size() || name.size() != changeAmount.size()) { Log.e(TAG, "updateAppUsages: Given arrays are of different length. This will not work"); } else { ArrayList<Integer> returnAmountArray = new ArrayList<>(); Cursor c = db.rawQuery(query, null); db.beginTransaction(); for (int i = 0; i < name.size(); i++) { c.moveToFirst(); while(!c.isAfterLast()){ if(c.getString(c.getColumnIndex("name")) != null){ if (c.getString(c.getColumnIndex("name")).equals(name.get(i))) { returnAmountArray.add(c.getInt(c.getColumnIndex("usages"))); break; } } c.moveToNext(); } returnAmountArray.add(0); if (action.get(i) == Action.INCREASE) { returnAmountArray.set(i, returnAmountArray.get(i) + changeAmount.get(i)); } else if (action.get(i) == Action.DECREASE) { returnAmountArray.set(i, returnAmountArray.get(i) - changeAmount.get(i)); if (returnAmountArray.get(i) < 0) { Log.e(TAG, "DBHandler; appUsages: 'returnAmount' below zero. Can't be less then nothing (" + returnAmountArray.get(i) + ")"); return; } } ContentValues values = new ContentValues(); if (returnArray(AppManagerUsages.AppManagerUsages, AMUStringArg.Name).contains(name.get(i))) { int id = returnID(Base.AppManagerUsages, name.get(i)); values.put(AT2_COLUMN_NAME, name.get(i)); values.put(AT2_COLUMN_USAGES, returnAmountArray.get(i)); db.update(TABLE_AppTable2, values, "_id=" + id, null); } else { values.put(AT2_COLUMN_NAME, name.get(i)); values.put(AT2_COLUMN_USAGES, returnAmountArray.get(i)); db.insert(TABLE_AppTable2, null, values); } } db.setTransactionSuccessful(); db.endTransaction(); c.close(); } if (db.isOpen()) { db.close(); } } 在任何地方都返回false(如果没有打开数据库,则会出现错误/ null)。

05-23 17:03:54.733 3671-3671/com.example.tim.timapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.tim.timapp, PID: 3671
java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/user/0/com.example.tim.timapp/databases/TimDatabase.db
    at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
    at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1439)
    at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1341)
    at com.example.tim.timapp.CustomStuff.DBHandler.updateAppUsages(DBHandler.java:566)
    at com.example.tim.timapp.CustomStuff.DBHandler.updateAppUsages(DBHandler.java:513)
    at com.example.fragments.MainFragments.DialogFragments.AppManagerInputDialog$1.onClick(AppManagerInputDialog.java:83)
    at android.view.View.performClick(View.java:5198)
    at android.view.View$PerformClick.run(View.java:21147)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5417)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
DecimalFormat

1 个答案:

答案 0 :(得分:0)

显然,这不是正确的做法。

here复制:

我不相信你每次都应该像这样获得一个新的SQLiteDatabase实例。您希望在SQLiteOpenHelper中保留对SQLiteDatabase对象的引用。您的SQLiteOpenHelper应该构造成类似于以下内容的东西:

public class DataBase extends SQLiteOpenHelper {

...
    private SQLiteDatabase mDatabase;

    @Override
    public void onCreate(SQLiteDatabase db) {
        ...
        mDatabase = db;
        ...
    }

....
}

结合this评论,我在自己的SQLiteOpenHelper课程中为自己创建了这个:

private static SQLiteDatabase db;

public static synchronized DBHandler getInstance(Context context) {
    if (sInstance == null) {
        sInstance = new DBHandler(context.getApplicationContext());
        db = sInstance.getWritableDatabase();
    }
    return sInstance;
}

到目前为止,这一直在运行干净并且没有给我任何错误,所以这里希望它保持这种状态。