Android架构组件Room的使用详解
Room其实就是一个orm,抽象了SQLite的使用,但是它作为Android的亲儿子orm,并且原生支持LiveData和Rxjava嵌套使用,学习一下还是不错的。
Room有3个主要组件
- Database:数据库
- Entity:代表数据库一个表结构
- Dao:包含访问数据库的方法
简单使用
添加GoogleMaven仓库
allprojects{
repositories{
jcenter()
google()
}
}
添加依赖
dependencies{
//Room
implementation"android.arch.persistence.room:runtime:1.0.0"
annotationProcessor"android.arch.persistence.room:compiler:1.0.0"
}
定义数据表实体类
班级表
@Entity(tableName="tb_class")
publicclassClassEntity{
@PrimaryKey
privatelongid;
}
学生表
//指示数据表实体类
@Entity(tableName="tb_student",//定义表名
indices=@Index(value={"name","sex"},unique=true),//定义索引
foreignKeys={@ForeignKey(entity=ClassEntity.class,
parentColumns="id",
childColumns="class_id")})//定义外键
publicclassStudentEntity{
@PrimaryKey//定义主键
privatelongid;
@ColumnInfo(name="name")//定义数据表中的字段名
privateStringname;
@ColumnInfo(name="sex")
privateintsex;
@Ignore//指示Room需要忽略的字段或方法
privateStringignoreText;
@ColumnInfo(name="class_id")
privateStringclass_id;
//setterandgetter
}
Entity注解可选参数
public@interfaceEntity{
//定义表名
StringtableName()default"";
//定义索引
Index[]indices()default{};
//设为true则父类的索引会自动被当前类继承
booleaninheritSuperIndices()defaultfalse;
//定义主键
String[]primaryKeys()default{};
//定义外键
ForeignKey[]foreignKeys()default{};
}
Index索引注解可选参数
public@interfaceIndex{
//定义需要添加索引的字段
String[]value();
//定义索引的名称
Stringname()default"";
//true-设置唯一键,标识value数组中的索引字段必须是唯一的,不可重复
booleanunique()defaultfalse;
}
ForeignKey外键注解可选参数
public@interfaceForeignKey{
//引用外键的表的实体
Classentity();
//要引用的外键列
String[]parentColumns();
//要关联的列
String[]childColumns();
//当父类实体(关联的外键表)从数据库中删除时执行的操作
@ActionintonDelete()defaultNO_ACTION;
//当父类实体(关联的外键表)更新时执行的操作
@ActionintonUpdate()defaultNO_ACTION;
//在事务完成之前,是否应该推迟外键约束
booleandeferred()defaultfalse;
//给onDelete,onUpdate定义的操作
intNO_ACTION=1;
intRESTRICT=2;
intSET_NULL=3;
intSET_DEFAULT=4;
intCASCADE=5;
@IntDef({NO_ACTION,RESTRICT,SET_NULL,SET_DEFAULT,CASCADE})
@interfaceAction{
}
}
定义Dao类
@Dao
publicinterfaceStudentDao{
@Query("SELECT*FROMStudentEntity")
ListgetAll();
@Query("SELECT*FROMStudentEntityWHEREidIN(:ids)")
ListgetAllByIds(long[]ids);
@Insert
voidinsert(StudentEntity...entities);
@Delete
voiddelete(StudentEntityentity);
@Update
voidupdate(StudentEntityentity);
}
@insert,@Update都可以执行事务操作,定义在OnConflictStrategy注解类中
public@interfaceInsert{
//定义处理冲突的操作
@OnConflictStrategy
intonConflict()defaultOnConflictStrategy.ABORT;
}
public@interfaceOnConflictStrategy{
//策略冲突就替换旧数据
intREPLACE=1;
//策略冲突就回滚事务
intROLLBACK=2;
//策略冲突就退出事务
intABORT=3;
//策略冲突就使事务失败
intFAIL=4;
//忽略冲突
intIGNORE=5;
}
定义数据库
@Database(entities={StudentEntity.class},version=1)
publicabstractclassRoomDemoDatabaseextendsRoomDatabase{
publicabstractStudentDaostudentDao();
}
生成数据库实例
RoomDemoDatabasedatabase=Room.databaseBuilder(getApplicationContext(),RoomDemoDatabase.class,"database_name") .build();
生成数据库实例的其他操作
Room.databaseBuilder(getApplicationContext(),
RoomDemoDatabase.class,"database_name")
.addCallback(newRoomDatabase.Callback(){
//第一次创建数据库时调用,但是在创建所有表之后调用的
@Override
publicvoidonCreate(@NonNullSupportSQLiteDatabasedb){
super.onCreate(db);
}
//当数据库被打开时调用
@Override
publicvoidonOpen(@NonNullSupportSQLiteDatabasedb){
super.onOpen(db);
}
})
.allowMainThreadQueries()//允许在主线程查询数据
.addMigrations()//迁移数据库使用,下面会单独拿出来讲
.fallbackToDestructiveMigration()//迁移数据库如果发生错误,将会重新创建数据库,而不是发生崩溃
.build();
数据库迁移(升级)
Room.databaseBuilder(getApplicationContext(),MyDb.class,"database-name")
.addMigrations(MIGRATION_1_2,MIGRATION_2_3).build();
staticfinalMigrationMIGRATION_1_2=newMigration(1,2){
@Override
publicvoidmigrate(SupportSQLiteDatabasedatabase){
database.execSQL("CREATETABLE`Fruit`(`id`INTEGER,"
+"`name`TEXT,PRIMARYKEY(`id`))");
}
};
staticfinalMigrationMIGRATION_2_3=newMigration(2,3){
@Override
publicvoidmigrate(SupportSQLiteDatabasedatabase){
database.execSQL("ALTERTABLEBook"
+"ADDCOLUMNpub_yearINTEGER");
}
};
创建嵌套对象
有时,您希望将一个实体或普通的以前的Java对象(POJO)作为数据库逻辑中的一个完整的整体来表示,即使该对象包含几个字段。在这些情况下,您可以使用@Embedded来表示一个对象,您希望将其分解为表中的子字段。然后可以像对其他单个列一样查询嵌入式字段
classAddress{
publicStringstreet;
publicStringstate;
publicStringcity;
@ColumnInfo(name="post_code")
publicintpostCode;
}
@Entity
classUser{
@PrimaryKey
publicintid;
publicStringfirstName;
@Embedded
publicAddressaddress;
}
这样user表中的字段就包含了id,firstName,street,state,city,和post_code
注意:嵌入式字段还可以包含其他嵌入式字段
如果一个实体具有相同类型的多个内嵌字段,则可以通过设置前缀属性(prefix)使每个列保持惟一。然后将所提供的值添加到嵌入对象中每个列名的开头
@Embedded(prefix="foo_") Coordinatescoordinates;
和LiveData一起使用
添加依赖
//ReactiveStreamssupportforLiveData implementation"android.arch.lifecycle:reactivestreams:1.0.0"
修改返回类型
@Dao
publicinterfaceMyDao{
@Query("SELECTfirst_name,last_nameFROMuserWHEREregionIN(:regions)")
publicLiveData>loadUsersFromRegionsSync(Listregions);
}
和RxJava一起使用
添加依赖
//RxJavasupportforRoom implementation"android.arch.persistence.room:rxjava2:1.0.0"
修改返回类型
@Dao
publicinterfaceMyDao{
@Query("SELECT*fromuserwhereid=:idLIMIT1")
publicFlowableloadUserById(intid);
}
直接游标访问
@Dao
publicinterfaceMyDao{
@Query("SELECT*FROMuserWHEREage>:minAgeLIMIT5")
publicCursorloadRawUsersOlderThan(intminAge);
}
类型转换
定义转换类,@TypeConverter注解定义转换的方法
publicclassConverters{
@TypeConverter
publicstaticDatefromTimestamp(Longvalue){
returnvalue==null?null:newDate(value);
}
@TypeConverter
publicstaticLongdateToTimestamp(Datedate){
returndate==null?null:date.getTime();
}
}
@TypeConverters注解,告知数据库要依赖哪些转换类
@Database(entities={User.class},version=1)
@TypeConverters({Converters.class})
publicabstractclassAppDatabaseextendsRoomDatabase{
publicabstractUserDaouserDao();
}
使用这些转换器,您可以在其他查询中使用您的自定义类型,正如您将使用基本类型一样,如下代码所示
@Entity
publicclassUser{
...
privateDatebirthday;
}
@Dao
publicinterfaceUserDao{
...
@Query("SELECT*FROMuserWHEREbirthdayBETWEEN:fromAND:to")
ListfindUsersBornBetweenDates(Datefrom,Dateto);
}
输出模式
在编译时,将数据库的模式信息导出到JSON文件中,这样可有利于我们更好的调试和排错
build.gradle
android{
...
defaultConfig{
...
javaCompileOptions{
annotationProcessorOptions{
arguments=["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
}
您应该将导出的JSON文件(表示数据库的模式历史记录)存储在您的版本控制系统中,因为它允许为测试目的创建您的数据库的旧版本
总结
以上所述是小编给大家介绍的Android架构组件Room的使用详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!