java - Android Room SQLite 数据迁移 - 尝试重新打开一个已经关闭的对象

标签 java android sqlite migration android-room

抱歉,如果这看起来是个愚蠢的问题。我对编程很陌生(3 周)。我添加了一个新的 Membership 表并编写了从 v3 到 4 的迁移,但它似乎不起作用。我列出了新表、用于迁移的代码以及我收到的错误消息。我花了几个小时尝试不同的事情。如果有人能指出我正确的方向,那将不胜感激。提前为糟糕的格式道歉。任何提供帮助的人都会有很棒的业力。

更新 - 已修复!

我终于明白了。这与我的迁移有关。

database.execSQL("CREATE TABLE Membership (mID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, mName TEXT, mBarcode TEXT, mType TEXT);");

这是我学到的知识和遵循的步骤。我希望这可以帮助其他人解决这个神秘的错误消息。

  1. 使用 Android SDK 平台工具 - adb root 获取模拟器
  2. adb pull/data/user/0/com.xxxx/databases/workout-database.db
  3. 使用 DB Browser for SQLite 打开数据库文件,了解 Room 的 CREATE TABLE 语句
  4. 在创建语句中,Room 做了一些“额外”的事情。所有 INTEGERS 都不是 NULL,ADD AUTOINCREMENT 到 PRIMARY KEY,十进制数是 REAL NOT NULL。

顺便说一句 - 这就是我认为消息发生的原因。如果您的架构根据您的迁移不完全匹配,Room 会恢复到原始版本并关闭数据库以保护它。然后,当它尝试在程序中的某处再次访问它时,它会失败并重新打开一个关闭的数据库错误。这只是一个猜测,但我认为它的工作原理有点像这样。基本上修复您的迁移,一切都很好。尝试理解 Room 如何创建数据库的另一种方法是,您可以尝试破译您的数据库类实现(单击数据库类中抽象 Dao 语句左侧的绿色按钮)。

错误日志

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.xxxx, PID: 5343
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxxx/com.xxxx.MainActivity}: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/user/0/com.xxxx/databases/workout-database
                  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2984)
                  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
                  at android.app.ActivityThread.-wrap14(ActivityThread.java)
                  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
                  at android.os.Handler.dispatchMessage(Handler.java:102)
                  at android.os.Looper.loop(Looper.java:154)
                  at android.app.ActivityThread.main(ActivityThread.java:6776)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
               Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/user/0/com.xxxx/databases/workout-database
                  at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
                  at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:2054)
                  at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:2000)
                  at android.arch.persistence.db.framework.FrameworkSQLiteDatabase.execSQL(FrameworkSQLiteDatabase.java:240)
                  at com.xxxx.data.utils.AppDatabase$1.migrate(AppDatabase.java:47)
                  at android.arch.persistence.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:73)
                  at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.java:118)
                  at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:256)
                  at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
                  at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:93)
                  at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)
                  at android.arch.persistence.room.RoomDatabase.query(RoomDatabase.java:193)
                  at com.xxxx.data.ExerciseDao_Impl.countExercises(ExerciseDao_Impl.java:275)
                  at com.xxxx.fragments.WorkoutSummaryFragment.onActivityCreated(WorkoutSummaryFragment.java:200)
                  at android.app.Fragment.performActivityCreated(Fragment.java:2361)
                  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1014)
                  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1171)
                  at android.app.BackStackRecord.run(BackStackRecord.java:815)
                  at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1582)
                  at android.app.FragmentController.execPendingActions(FragmentController.java:372)
                  at android.app.Activity.performStart(Activity.java:6971)
                  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2937)
                  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045) 
                  at android.app.ActivityThread.-wrap14(ActivityThread.java) 
                  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642) 
                  at android.os.Handler.dispatchMessage(Handler.java:102) 
                  at android.os.Looper.loop(Looper.java:154) 
                  at android.app.ActivityThread.main(ActivityThread.java:6776) 
                  at java.lang.reflect.Method.invoke(Native Method) 
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520) 
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410) 
Application terminated.

数据库类

@Database(entities = {Workout.class, Exercise.class, Membership.class}, version = 4)

public abstract class AppDatabase extends RoomDatabase {

private static AppDatabase INSTANCE;

public abstract WorkoutDao workoutDao();
public abstract ExerciseDao exerciseDao();
public abstract MembershipDao membershipDao();

public static AppDatabase getAppDatabase(Context context) {
    if (INSTANCE == null) {
        INSTANCE =
                Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "workout-database")
                        //.fallbackToDestructiveMigration()
                        .addMigrations(MIGRATION_3_4)
                        .build();
    }
    return INSTANCE;
}

static final Migration MIGRATION_3_4 = new Migration(3, 4) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        // Create the new table
        database.execSQL("CREATE TABLE Membership (mID INTEGER, mName TEXT, mBarcode TEXT, mType TEXT, PRIMARY KEY(mID))");
    }
};

public static void destroyInstance() {
    INSTANCE = null;
}

}

最佳答案

参见上面的更新。尽管错误消息是这样说的,但问题出在迁移上

关于java - Android Room SQLite 数据迁移 - 尝试重新打开一个已经关闭的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49265130/

相关文章:

java - 如何获取 setOnItemSelectedListener 之外的变量的更新值?

android - Android NDK 中的链接器错误(对 `__cxa_end_cleanup' 的 undefined reference )

sqlite - 如何使用多个 WHERE 子句进行 DELETE [SQLITE]

java - 我不断收到 Java 错误 "cannot find or load main class",但 javac 在执行时工作正常

java - ArrayList—indexOf(T t) 方法的实现

android - 在 Android 中添加 "splits"后出现错误 : Could not find EOCD,

当我尝试复制一个字符串时,Android NDK strcpy 崩溃

c++ - 如何使用 SQLite 在 qt 中创建表?

sql - 使用sum函数过滤掉表中的随机行

java - Spring Security 使用 RequestParam 时不断要求登录