官方教程
一、配置依赖
dependencies {
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// 可选 - RxJava2 support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// 可选 - RxJava3 support for Room
implementation "androidx.room:room-rxjava3:$room_version"
// 可选 - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// 可选 - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
// 可选 - Paging 3 Integration
implementation "androidx.room:room-paging:2.4.0-alpha05"
}
如果是kotlin项目可以添加kotlin-kapt插件,然后更改annotationProcessor为kapt,示例如下
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
...
dependencies {
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
}
二、创建表
Room是一个对象一张表,所以在要存储的bean上添加@Entity,框架就会自动建表。示例如下
@Entity(tableName = "history",primaryKeys = {
"uid","vid"})
public class HistoryBean {
private int uid;
@NonNull
private String vid = "";
@ColumnInfo(name = "title", typeAffinity = ColumnInfo.TEXT)
private String title;
@Ignore
...
}
tableName属性可以为该表设置名字,如果不设置,则表名与类名相同。
@ColumnInfo标签可用于设置该字段存储在数据库表中的名字并指定字段的类型。
@Ignore顾名思义,数据库忽略该字段
三、定义表操作(增删改查)
新建一个接口,添加@Dao注解,然后定义增删改查的方法,框架会自动实现,示例如下
@Dao
public interface HistoryDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
public void setHistory(HistoryBean historyBean);
@Update
public void updateHistory(HistoryBean historyBean);
@Delete
public void deleteHistory(HistoryBean historyBean);
@Query("select * from history order by viewTime desc")
public List<HistoryBean> getAllHistory();
@Query("select * from history where uid = :uid and vid = :vid")
public HistoryBean findHistory(int uid,String vid);
}
四、创建数据库
@Database(entities = {
HistoryBean.class},version = 1,exportSchema = false)
@TypeConverters({
AppBaseConverter.class})
public abstract class AppBaseDatabase extends RoomDatabase {
private static class AppBaseDatabaseHolder {
private static final AppBaseDatabase instance = Room.databaseBuilder(BIPApp.getInstance(),AppBaseDatabase.class,"baseDb").fallbackToDestructiveMigration().build();
}
public static AppBaseDatabase getInstance() {
return AppBaseDatabase.AppBaseDatabaseHolder.instance;
}
abstract HistoryDao getHistoryDao();
}
@TypeConverters注解是可选的,用于转换数据库无法识别的数据类型,比如自定义类,示例如下
public class AppBaseConverter {
@TypeConverter
public String List2String(List<VideoListBean> data){
return new Gson().toJson(data);
}
@TypeConverter
public List<VideoListBean> String2List(String data){
return new Gson().fromJson(data,new TypeToken<List<VideoListBean>>(){
}.getType());
}
}
完成上面操作后就可以正常使用了,比如
AppBaseDatabase.getInstance().getHistoryDao().getAllHistory();
五、迁移数据库
当表结构变化或者增加新的表时需要迁移数据库,比如有版本1升级到版本2,增加了一张表,那么需要在entities里加上表类,更新版本号。示例如下
@Database(entities = {
HistoryBean.class, DownloadInfoBean.class}, version = 2)
增加了DownloadInfoBean然后更新了version。接着定义一个Migration,示例如下
static final Migration MIGRATION1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS `download` (`mediaId` TEXT NOT NULL, `title` TEXT, `sourceUrl` TEXT, `downloadState` INTEGER NOT NULL, `localPath` TEXT, `contentLength` INTEGER NOT NULL, `cover` TEXT, `downloadUrl` TEXT, `coverPortrait` INTEGER NOT NULL, `duration` INTEGER NOT NULL, `downloadTime` INTEGER NOT NULL, `sourceName` TEXT, `videoData` TEXT, `selectSourceIndex` INTEGER NOT NULL, `downloadTargetPosition` INTEGER NOT NULL, `downloadingProgress` INTEGER NOT NULL, PRIMARY KEY(`mediaId`))");
}
};
上面的数字1和2对应版本号,表示数据库由1升级到2时会触发这个Migration。可以跨版本升级(比如你定义了1~3的Migration,在从1升级到3时就会调用他,否则依次调用1-2,2-3)。上面就是新建了DownloadInfoBean对应的表。建表语句可以通过设置exportSchema=true然后在项目build.gradle文件指定schema导出位置,就能看到导出的schema。示例如下
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
最后在获取数据库实例时通过addMigrations传入Migration,示例如下
private static final AppBaseDatabase instance = Room.databaseBuilder(BIPApp.getInstance(), AppBaseDatabase.class, "appDb").addMigrations(MIGRATION1_2).build();
如果没有配置对应的Migration,当配置了fallbackToDestructiveMigration时会清空数据库数据,如果连fallbackToDestructiveMigration都没配置则会发生崩溃。
自动迁移
版本2.4.0后提供了一个自动迁移的API,就不细讲了放一下官方示例代码,感兴趣的自行了解(需要注意使用自动迁移exportSchema一定要是true)。
@Database(
version = MusicDatabase.LATEST_VERSION,
entities = [
Song.class,
Artist.class
],
autoMigrations = [
@AutoMigration (
from = 1,
to = 2
),
@AutoMigration (
from = 2,
to = 3,
spec = MusicDatabase.MyExampleAutoMigration::class
)
],
exportSchema = true
)
abstract class MusicDatabase : RoomDatabase() {
const val LATEST_VERSION = 3
@DeleteTable(deletedTableName = "Album")
@RenameTable(fromTableName = "Singer", toTableName = "Artist")
@RenameColumn(
tableName = "Song",
fromColumnName = "songName",
toColumnName = "songTitle"
)
@DeleteColumn(fromTableName = "Song", deletedColumnName = "genre")
class MyExampleAutoMigration : AutoMigrationSpec {
@Override
override fun onPostMigrate(db: SupportSQLiteDatabase) {
// Invoked once auto migration is done
}
}
}