我有一个与
SQLite
数据库运行良好的应用程序。我想升级到 Room
,我按照 this 和 this 文章来测试并从 SQLite 升级到 Room。
我创建了
Entities
、DAO
和 Database
课程。
以下是我的(build.gradle:app)
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "APP ID"
minSdkVersion 20
targetSdkVersion 28
versionCode 10
versionName "1.4.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
repositories {
maven {
url 'http://dl.bintray.com/amulyakhare/maven'
}
}
}
dependencies {
def room_version = "1.1.1"
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Core library
androidTestImplementation 'androidx.test:core:1.0.0'
androidTestImplementation "androidx.test.ext:junit:1.0.0"
androidTestImplementation 'androidx.test:rules:1.1.0'
androidTestImplementation 'android.arch.persistence.room:testing:1.1.1'
implementation "androidx.room:room-runtime:2.1.0-alpha03"
implementation "androidx.appcompat:appcompat:1.0.2"
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
implementation 'com.googlecode.libphonenumber:libphonenumber:8.8.1'
implementation 'com.facebook.stetho:stetho:1.5.0'
implementation 'com.google.android.material:material:1.1.0-alpha01'
implementation 'com.hbb20:ccp:2.0.3'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.google.firebase:firebase-ads:11.4.2'
implementation 'com.google.firebase:firebase-crash:11.4.2'
}
以下是创建数据库副本的测试类
public class SqliteTestDbOpenHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 10;
public SqliteTestDbOpenHelper(Context context, String databaseName) {
super(context, databaseName, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + ContactsDBContract.ContactsTable.TABLE_CONTACTS +
"(" +
ContactsDBContract.ContactsTable._ID + " INTEGER PRIMARY KEY," + // Define a primary key
ContactsDBContract.ContactsTable.CONTACT_ID + " TEXT, " +
ContactsDBContract.ContactsTable.CONTACT_LOOKUP_KEY + " TEXT, " +
ContactsDBContract.ContactsTable.CONTACT_MESSAGE+ " TEXT, " +
ContactsDBContract.ContactsTable.CONTACT_NAME+ " TEXT, " +
ContactsDBContract.ContactsTable.CONTACT_PHONE_NUMBER + " TEXT, " +
ContactsDBContract.ContactsTable.CONTACT_DATA_VERSION+ " TEXT, " +
ContactsDBContract.ContactsTable.CONTACT_STAMP_STATUS+ " TEXT, " +
ContactsDBContract.ContactsTable.CONTACT_MIMETYPE+ " TEXT, " +
ContactsDBContract.ContactsTable.IS_BLOCK+ " INTEGER " +
")";
String CREATE_BLOCK_TABLE = "CREATE TABLE " + ContactsDBContract.BlockTable.TABLE_BLOCKS +
"(" +
ContactsDBContract.BlockTable._ID + " INTEGER PRIMARY KEY," + // Define a primary key
ContactsDBContract.BlockTable.BLOCK_CONTACT_PHONE_NUMBER + " TEXT, " +
ContactsDBContract.BlockTable.BLOCK_CONTACT_NAME+ " TEXT " +
")";
String CREATE_SCHEDULE_TABLE="CREATE TABLE " + ContactsDBContract.ScheduleTable.SCHEDULE_TABLE +
"(" +
ContactsDBContract.ScheduleTable._ID + " INTEGER PRIMARY KEY," + // Define a primary key
ContactsDBContract.ScheduleTable.SCHEDULE_START_TIME + " TEXT, " +
ContactsDBContract.ScheduleTable.SCHEDULE_END_TIME+ " TEXT " +
")";
try {
db.execSQL(CREATE_BLOCK_TABLE);
db.execSQL(CREATE_CONTACTS_TABLE);
db.execSQL(CREATE_SCHEDULE_TABLE);
} catch (SQLException e) {
e.printStackTrace();
FirebaseCrash.report(e);
}
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Not required as at version 1
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Not required as at version 1
}
}
下面是我的房间数据库课程
@Database(entities = {ContactsData.class,SchedulesData.class,BlocksData.class}, version = 11,exportSchema = true)
public abstract class DatabaseManager extends RoomDatabase {
private DatabaseManager database;
public abstract ContactDao contactsDao();
public abstract SchedulesDao schedulesDao();
public abstract BlocksDao blocksDao();
@VisibleForTesting
public static Migration MIGRATION_10_11 = new Migration(10,11) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
// nothing to do because we did not change anything
}
};
public DatabaseManager getInstance(Context context){
if(database == null){
database = Room.databaseBuilder(context.getApplicationContext(),DatabaseManager.class,"ContactsDB,db")
.addMigrations(MIGRATION_10_11).build();
}
return database;
}
}
下面是我的迁移测试类
@RunWith(AndroidJUnit4.class)
public class MigrationTest {
private static final String TEST_DB_NAME = "Contactsdb";
// Helper for creating Room databases and migrations
@Rule
public MigrationTestHelper mMigrationTestHelper =
new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
DatabaseManager.class.getCanonicalName(),
new FrameworkSQLiteOpenHelperFactory());
// Helper for creating SQLite database in version 1
private SqliteTestDbOpenHelper mSqliteTestDbHelper;
@Before
public void setUp() throws Exception {
// To test migrations from version 1 of the database, we need to create the database
// with version 1 using SQLite API
mSqliteTestDbHelper = new SqliteTestDbOpenHelper(ApplicationProvider.getApplicationContext(),
TEST_DB_NAME);
// We're creating the table for every test, to ensure that the table is in the correct state
SqliteDatabaseTestHelper.createTable(mSqliteTestDbHelper);
}
@After
public void tearDown() throws Exception {
// Clear the database after every test
SqliteDatabaseTestHelper.clearDatabase(mSqliteTestDbHelper);
}
@Test
public void migrationFrom1To2_containsCorrectData() throws IOException {
// Create the database with the initial version 1 schema and insert a user
SqliteDatabaseTestHelper.addContact(mSqliteTestDbHelper);
// Create the database with the initial version 1 schema and insert a user
//SqliteDatabaseTestHelper.insertContact(1, "zaid", mSqliteTestDbHelper);
mMigrationTestHelper.runMigrationsAndValidate(TEST_DB_NAME, 11, true,
MIGRATION_10_11);
// Get the latest, migrated, version of the database
DatabaseManager latestDb = getMigratedRoomDatabase();
// Check that the correct data is in the database
List<ContactsData> dbUser = latestDb.contactsDao().getAll();
assertThat(dbUser.size(),is(1));
}
@Test
public void startInVersion2_containsCorrectData() throws IOException {
// Create the database with version 2
SupportSQLiteDatabase db = mMigrationTestHelper.createDatabase(TEST_DB_NAME, 3);
// db has schema version 2. insert some data
insertContact(db);
db.close();
// open the db with Room
DatabaseManager usersDatabase = getMigratedRoomDatabase();
// verify that the data is correct
// Get the latest, migrated, version of the database
DatabaseManager latestDb = getMigratedRoomDatabase();
// Check that the correct data is in the database
List<ContactsData> dbUser = latestDb.contactsDao().getAll();
assertThat(dbUser.size(),is(1));
}
private DatabaseManager getMigratedRoomDatabase() {
DatabaseManager database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(),
DatabaseManager.class, TEST_DB_NAME)
.addMigrations(MIGRATION_10_11)
.build();
// close the database and release any stream resources when the test finishes
mMigrationTestHelper.closeWhenFinished(database);
return database;
}
private void insertContact(SupportSQLiteDatabase db) {
ContentValues cv=new ContentValues();
cv.put(ContactsDBContract.ContactsTable.CONTACT_ID,"212222");
cv.put(ContactsDBContract.ContactsTable.CONTACT_NAME,"Moti");
cv.put(ContactsDBContract.ContactsTable.CONTACT_LOOKUP_KEY,"Okay-uuss");
cv.put(ContactsDBContract.ContactsTable.CONTACT_PHONE_NUMBER,"03215467845");
db.insert(ContactsDBContract.ContactsTable.TABLE_CONTACTS, SQLiteDatabase.CONFLICT_REPLACE, cv);
}
}
但是当我运行/调试
migrationFrom1To2_containsCorrectData()
测试时。我收到以下错误
Cannot find the schema file in the assets folder. Make sure to include the exported json schemas in your test assert inputs. See https://developer.android.com/topic/libraries/architecture/room.html#db-migration-testing for details. Missing file: package.dummy.manager.DatabaseManager/11.json
按照官方文档中的解释,似乎没有在编译时创建模式。可能是我理解有误
这个技巧的目的如下:
在应用程序模块的应用程序 build.gradle 文件中添加以下定义:
android {
………
defaultConfig {
………
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
// *** For Kotlin ****
// kapt {
// arguments {
// arg("room.schemaLocation", "$projectDir/schemas".toString())
//
// }
}
和
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // use kapt for Kotlin
您的 Android Room 初始设置不正确。您错过了它的注释处理器依赖性。从官方文档中,您可以在这里找到添加组件#Room - 对于 AndroidX,您应该有两行:
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // use kapt for Kotlin
然后重建项目并查看内部
$projectDir/schemas
文件夹:您的架构应该在里面。
如果使用 ksp:
android {
...
defaultConfig {
...
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
}
}
}