【发布时间】:2018-03-13 20:15:37
【问题描述】:
抱歉,这似乎是一个愚蠢的问题。我对编程很陌生(3 周)。我添加了一个新的 Membership 表并编写了从 v3 到 4 的迁移,但它似乎不起作用。我列出了新表、用于迁移的代码以及我收到的错误消息。我花了几个小时尝试不同的东西。如果有人能指出我正确的方向,那将不胜感激。提前为糟糕的格式道歉。任何有帮助的人都会得到很棒的业力。
更新 - 已修复!
我终于明白了。这是我的迁移。
database.execSQL("CREATE TABLE Membership (mID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, mName TEXT, mBarcode TEXT, mType TEXT);");
这是我学到的知识和我遵循的步骤。我希望这可以帮助其他人处理这个神秘的错误消息。
- 使用 Android SDK 平台工具 - adb root 对模拟器进行了 Root
- adb pull /data/user/0/com.xxxx/databases/workout-database.db
- 使用 DB Browser for SQLite 打开数据库文件以了解 Room 执行的 CREATE TABLE 语句
- 在创建语句中,Room 做了一些“额外”的事情。所有 INTEGERS 都不为 NULL,将 AUTOINCREMENT 添加到 PRIMARY KEY,十进制数是 REAL NOT NULL。
顺便说一句 - 这就是我认为消息发生的原因。如果您的架构与您的迁移不完全匹配,Room 将恢复为原始版本并关闭数据库以保护它。然后,当它尝试在程序中的某个位置再次访问它时,它会因重新打开已关闭的数据库错误而失败。这只是一个猜测,但我认为它有点像这样。基本上修复你的迁移,一切都很好。另一种尝试了解 Room 如何创建数据库的方法是,您可以尝试解读您的 Database 类实现(单击 Database 类中抽象 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;
}
}
【问题讨论】:
-
attempt to re-open an already-closed object-- 你是手动关闭你的RoomDatabase吗? -
我不这么认为。所有的数据库管理都由这个类和一个初始化程序处理。当我删除迁移并返回 v3 时,一切正常。我怀疑我的迁移错误导致了导致此错误的空数据库或空数据库。但我真的不知道。我应该手动关闭吗?我认为 Room 可以处理所有爵士乐。
-
"我应该手动关闭吗?" -- 不,但这就是为什么我试图弄清楚为什么 Room 说对象已经关闭。
标签: java android sqlite migration android-room