从架构设计角度分析AAC源码-Room注解使用大全(基于2.4版本源码解析)(一)
前言
本篇单纯讲解Room源码,和前后篇章没有关系。
当前Room注解大全是基于Room2.4版本代码逻辑得来,如果有问题欢迎给予指正。当前Room源码学习目的:(1)主要原因:学习jetpack代码;(2)次要原因:网上看了很多相关Room注解使用,非常肤浅(可能个人眼界有限,没有找到真正比较全面的注解),所以想自己看代码去全面理解一下room注解;
之前有了dagger2(基于2.38.1版本)注解理解基础,所以这里相对来说理解起来较简单,也是相当来说而已,代码看起来还是头疼得很!!!
前提
理解Room注解前提条件:
必须!!!是必须理解sql数据库相关操作!!!如果想全面理解当前Room,那么不但对数据库基本操作熟悉,对其他如视图、索引也要有一定了解,这样才会事半功倍。
以下讲解围绕数据库创建和数据库操作两部分讲解:
- 数据库创建
- 1.1 通过Room注解实现数据库创建的规则
- 1.2 如何通过Room注解创建数据库
- 操作数据库
- 2.1 通过Room注解操作数据库规则
- 2.2 Room注解如何操作数据库
还会细分,创建数据库有表、视图、关系、表字段等;操作数据库又分为对数据库增删改查,还有事务等。
下面根据数据库创建和操作来对Room注解一一解析,并且按照常用在前,不常用在后原则慢慢品味源码。
术语解释
这里是我自己命名的一些词语。相当于一个给下面的Room注解有些名词进行解释,这里先不需要看,等看到下面具体的名词的时候回到这里来看。
表字段:表或视图的字段;
xx节点:表示使用@Xx注解修饰的节点,e.g.@Entity修饰的节点表示entity节点;
fts节点:@Fts3或@Fts4修饰的 entity节点;
pojo节点:下面有一个篇章专门介绍pojo对象的生成,表示能生成Pojo对象的节点;
pojo节点有效方法:非private修饰 && 非abstract修饰 && 非@Ignore修饰;
pojo节点setter方法:有且仅有一个参数,返回类型是void;
pojo节点getter方法:pojo节点有效方法中,无参,返回类型不是void;
表有效字段:pojo节点中所有字段(包括父级类中的字段),并且该字段满足 : 没有被@Ignore修饰 && 不是static修饰 && (没有使用transient修饰 || (使用了@ColumnInfo或@Embedded或Relation修饰));
表常规字段:表有效字段中使用@ColumnInfo修饰 或 没有使用transient修饰的表字段;如果当前字段表示的节点使用@Entity修饰,那么不存在于@Entity#ignoredColumns中;
表关系字段:表有效字段中使用@Relation修饰;
表嵌入字段:表有效字段中使用@Embedded修饰;如果当前字段表示的节点使用@Entity修饰,那么不存在于@Entity#ignoredColumns中;
嵌入表:表有效字段中使用@Embedded修饰的字段对象生成的表;
关系表:表有效字段中使用@Relation修饰的字段对象生成的表;
Room注解规则大全
感觉名字是不是有点大!!!可能有那么一点,但是我把源码中关于Room注解的逻辑全部提炼出来也就那么回事儿。
来来回回一遍遍去理解,花的都是心血啊,如果对读者有帮助,必须给个star。
1. Room注解创建数据库规则
一切都是从@Database注解说起,使用当前注解拉开Room注解篇章,从此踏上不归路,呸呸呸…从此走上人生癫疯!!!嗯,癫疯!
前言:Pojo对象生成规则
本篇核心规则之一:必须先理解,而且这么去写。
用于创建Pojo的节点:
情况一:数据库创建过程中生成Pojo对象:
entity节点:@Entity修饰的节点;
fts节点:@Fts3或@Fts3修饰的节点同时使用@Entity修饰;
databaseView节点:@DatabaseView修饰的节点;
embedded修饰的节点类型:@Embedded修饰的节点类型,该表示的对象节点;
情况二:数据库操作过程中创建Pojo对象:
生成Pojo对象规则:
pojo节点生成pojo对象过程中,有可能pojo节点中的子节点又生成一个子pojo对象,正确情况下(肯定存在非正常情况,感兴趣自己看源码)不能出现pojo对象循环引用,e.g.该子pojo节点类型就是该父级pojo节点类型;
正常情况下,pojo节点的所有方法不允许使用@PrimaryKey, @ColumnInfo,@Embedded, @Relation修饰;但是如果pojo节点同时使用@AutoValue修饰,规则如下:
- (1)pojo节点只允许存在无参abstract修饰的方法,并且允许使用@PrimaryKey, @ColumnInfo,@Embedded, @Relation修饰;
- (2)pojo节点的方法如果使用了androidx.room包下的注解,那么该方法最好使用@CopyAnnotations注解,否则会提示警告;
如果pojo节点是entity节点,那 @Entity#ignoredColumns属性表示被忽略的字段,被忽略的字段只允许是表常规字段和表嵌入字段;
表常规字段和嵌入表常规字段不允许重复;
pojo节点构造函数,筛选条件:
(1)pojo节点(没有使用@AutoValue修饰)构造函数条件:当前构造函数没有被@Ignore修饰 || 当前构造函数不是private修饰;如果pojo节点被@AutoValue修饰,那么 : 方法没有被@Ignore修饰 && 方法没有被private修饰 && 方法是static修饰 && 方法返回类型是当前类类型;
(2)构造函数参数筛选:
① 如果pojo节点的构造函数参数是当前pojo生成的表常规字段、表嵌入字段或表关系字段,则没有问题;
② 如果不满足条件①,那么:要么表常规字段、表嵌入字段或表关系字段都不存在;要么有且仅有一个表字段(常规、关系或嵌入中的一个),也就说该情况下允许构造函数参数不匹配表字段情况;否则都报错;
(3)如果经过以上筛选存在一个构造函数,并且该构造函数要有参数;如果存在多个构造函数,是kotlin语言直接返回主构造函数,不存在主构造函数,存在参数为空的构造函数则警告;多个构造函数筛选出第一个即可;
- 校验pojo节点的常规字段的setter和getter方法:
除了pojo节点常规字段,还有嵌入表的常规字段、关系表的常规字段和嵌入表中的关系表的常规字段。
(1)如果pojo节点中的变量存在于构造函数中,那么不需要校验setter方法;否则按照如下顺序一步步校验;
(2)变量如果是public修饰,不需要校验setter和getter方法;
(3)如果setter和getter方法不是public修饰,那么当前变量不是private修饰,也表示校验成功;
(4)setter和getter方法分别最多只能存在一个;如果存在多个报错;
(5)除了以上情况,其他情况报错;
对象属性:
element:用于创建Pojo的节点;如果节点同时使用@AutovAlue表示新生成的节点:Auto_原先节点;
type:用于创建Pojo的节点类型;如果节点同时使用@AutovAlue表示新生成的节点类型:Auto_原先节点类型;
fields:表常规字段 + 嵌入表常规字段;
embeddedFields:pojo节点中的embedded节点生成的对象;
relations:pojo节点中的relation节点生成的对象;
constructor:pojo节点构造函数。
1.0 创建数据库文件规则
使用@Database注解的节点,表示生成一个数据库文件。
一个项目中@Database注解可以存着多个,表示生成多个数据库文件;
@Database#entities属性表示在当前数据库文件中创建表信息:必须存在,属性值类型对象,必须使用@Entity修饰;
@Database#views表示创建视图信息:属性值类型对象必须使用@DatabaseView修饰;
@Database修饰的类必须继承
androidx.room.RoomDatabase
类;一定要确保每个数据库文件中的@Database#entities和@Database#views中的表和视图名称不重复;
@Database修饰的类必须是abstract抽象类,其abstract(非RoomDatabase继承过来的)抽象方法:
- (1)不能使用@JvmName修饰,否则警告;
- (2)当前方法返回类型对象必须被@Dao修饰,表示对该数据库文件的操作;
1.1 普通表规则
@Entity注解修饰的类表示数据库中的表信息。
- 表名:使用@Entity#tableName;如果不存在,使用@Entity修饰的类名;
- (1)一个数据库文件中的表名唯一;
- (2)表名不允许使用“sqlite_”前缀;
- (3)表名不允许使用 ` 或 " 特殊字符;
- @Entity#indices:索引;
- (1) 嵌入表常规字段不要创建索引,否则警告
- (2)当前索引字段如果是entity节点继承过来的,那么必须设置当前entity的@Entity#inheritSuperIndices = true;否则警告,并且该索引无效;
@Entity#inheritSuperIndices:默认false;如果为true,表示当前@Entity修饰的类的父类如果也使用了@Entity修饰,那么继承其父类的@Entity#indices索引;
@Entity#foreignKeys:表外键;
entity节点的所有方法不允许使用@PrimaryKey、 @ColumnInfo、@Embedded和@Relation修饰;但是:如果entity节点同时使用了@AutoValue修饰,那么:
(1)entity节点下的方法允许使用@PrimaryKey、 @ColumnInfo、@Embedded和@Relation修饰;
(2)entity节点下的无参抽象方法(该类只允许存在无参抽象方法)如果使用了androidx.room包下的注解,那么最好无参抽象方法也是用@CopyAnnotations修饰,否则报警告;
@Entity#ignoredColumns表示忽略的表字段;哪些表字段可以被忽略:①表常规字段;②表嵌入字段;
@Entity#primaryKeys表示表的主键;
@Entity修饰的节点可以生成pojo对象,所以需要按照参照生成pojo对象规则;
@Entity修饰的类中不允许出现@Relation修饰的有效字段;
1.1.1 fts表规则
entity节点同时使用@Fts3或@Fts4修饰的节点,称之为fts表。
fts表属性和规则如下:
@Fts3#tokenizer:FTS3表中使用的标记器;
@Fts3#tokenizerArgs:FTS3表中用于配置定义的标记器的可选参数;
@Fts4#tokenizer:FTS4表中使用的标记器;
@Fts4#tokenizerArgs:FTS4表中用于配置定义的标记器的可选参数;
@Fts4#contentEntity:FTS4表映射表的外部内容实体将用作FTS表的内容;
(1)当前属性必须存在,并且是使用@Entity注解修饰的类;
(2)fts表中除了rowid主键和languageId(@Fts4#languageId)字段,其他字段必须存在于@Fts4#contentEntity中属性对象生成的表常规字段或嵌入表常规字段中;
(3)@Fts4#contentEntity中的对象必须存在于@Database#entities中
- @Fts4#languageId:FTS4表要用作“languageid”的字段;
- (1)languageid字段必须存在于fts表常规字段或嵌入表常规字段中;
- (2)languageid字段必须是int类型;
@Fts4#matchInfo:Fts版本,这里只有FTS3和FTS4两个版本;
@Fts4#notIndexed:FTS4表上不会被创建索引的表字段;
- 该表字段必须存在于fts表常规字段或嵌入表常规字段中;
- @Fts4#prefix:FTS4表索引前缀;
- 必须大于0
@Fts4#order:FTS表的首选“rowid”顺序;
表名::@Entity#tableName属性值如果存在,则使用该属性值;否则使用@Entity修饰的类名;
fts表不允许创建索引,不允许使用外键
- 对于索引,代码中仅仅支出不允许使用@Entity#indices来使用索引;
fts节点也可以生成pojo对象,所以fts节点必须满足pojo对象生成规则;
fts表不允许存在表关系字段(@Relation修饰的有效变量);
影子表名:
- (1)如果是@Fts3修饰,那么使用:表名 + “_content”;
- (2)如果是@Fts4修饰,那么使用:@Fts4#contentEntity中
的类型对象生成的表名;
- fts表必须存在主键是rowid的表字段,并且当前字段类型是int;主键有且仅有一个,(原则上主键可以有多个字段,但是必须保证第一个是rowid);
1.2 视图规则
@DatabaseView注解修饰的类表示数据库中视图信息。
视图如何使用:
@Database#views;
@Relation修饰的表关系对象使用@DatabaseView;
@Relation#associateBy#value中的对象使用@DatabaseView,表示多对多关系,e.g.
@Relation(parentColumn = "playlistId",entity = Song::class,entityColumn = "songId",associateBy = @Junction(value = PlaylistSongXRef::class,parentColumn = "pId",entityColumn = "sId"))
注①:@Relation注解不能修饰@Entity修饰的类的有效字段;
注②:外键指向的必须是@Entity修饰的对象表;
视图属性和使用规则如下:
@DatabaseView#vlue属性表示select查询:当前属性必须存在,并且是正确的select语句;
@DatabaseView#viewName属性表示视图名称:如果当前属性不存在,则使用@DatabaseView修饰的节点名称作为视图名称;
视图名称不能使用"sqlite_"前缀;
视图节点可以用于床架pojo对象,所以必须满足生成pojo对象规则。
1.3 表字段规则
pojo节点中的变量用于生成表字段,有三种类型:表常规字段,表嵌入字段和表关系字段(看术语解释)。
1.3.1 表常规字段
表有效字段中使用@ColumnInfo修饰 或 没有使用transient修饰的表字段;如果当前字段表示的节点使用@Entity修饰,那么不存在于@Entity#ignoredColumns中。
@ColumnInfo注解属性:
@ColumnInfo#name作为表字段名称;
@ColumnInfo#typeAffinity表示表字段偏向类型;
@ColumnInfo#index表示表字段是否创建索引;默认false
@ColumnInfo#collate表示当前表字段排序规则;
@ColumnInfo#defaultValue表示当前表字段默认值;
表常规字段规则如下:
- 表名:使用@ColumnInfo#name(非默认[field-name])属性值;如果不存在则直接使用当前变量名作为表名,还存在一种情况:
- (1)如果当前表字段是嵌入表中的字段,那么表名 = @Embedded#prefix + 当前表名;
- (2)表常规字段不允许使用 ` 或 " 特殊字符
- 表字段支持类型(重要):
2.1 如果表字段类型是泛型,那么必须是实体泛型,例如List是正确的泛型格式,List< T>格式错误;
2.2 表字段类型,根据当前变量类型确定生成的表字段类型,如果不存在于:
(1) TEXT-文本类型:
① String类型;
(2) INTEGER-int类型:
① int、short、byte、long和char四种基本类型;
② Integer、Short、Byte和Long四种基本类型的包装类型;
③ boolean或Boolean,当前源码会自动将其转换成int类型,true使用1表示,false使用0表示,所以boolean和Boolean生成INTEGER类型表字段;
(3) REAL-长int类型:
① float和double基本类型;
② Float和Double基本类型的包装类型;
(4) BLOB-长文本类型:
① byte[]
② ByteBuffer类型
(5)使用@ColumnInfo修饰表常规字段,@ColumnInfo#typeAffinity表示当前表字段偏向类型,最好不设置。
① 设置了@ColumnInfo#typeAffinity,首先根据变量类型去匹配表字段类型,如果匹配成功,再根据匹配的表字段类型是否等于我们设置的表字段偏向类型,如果没有匹配上,则表示当前适配不成功,继续往下匹配;
② 没有设置@ColumnInfo#typeAffinity,就不会存在(5)①中的再次匹配偏向类型的情况;
(6)如果变量类型不属于以上四种类型,那么还会通过在@TypeConverters修饰的节点实现类型转换(自行查看下面类型转换篇章),最终也是转换成以上四种类型;
(7)以上条件都不满足,还有一种特例,变量类型是枚举或UUID类型,有可能(是有可能,这种情况基本不可能)也会生成对应的类型;
(8)以上条件都不满足,那么肯定会报错;
1.3.2 表嵌入字段
表嵌入字段,@Embedded修饰的字段。
@Embedded#prefix属性,表示当前@Embedded修饰的变量对象中的变量生成表字段的需要添加的前缀。
规则如下:
@Embedded修饰的有效字段类型必须是类或接口;
@Embedded修饰的有效字段类型,不能存在递归引用。e.g.@Entity修饰的节点和@Entity节点中@Embedded修饰的节点类型一致,则表示递归,肯定不被允许;
当前@Embedded修饰的节点类型会生成Pojo对象;
1.3.3 表关系字段
表关系字段,@Relation修饰的字段。
@Relation注解属性:
@Relation#entity属性:存放对象类型必须使用@Entity修饰或@DatabaseView修饰;表示当前表或视图关联的表或视图对象;
@Relation#parentColumn属性:当前表字段(一般是外键),用于关联@Relation#entity对象(一般关联的的是主键)信息;
@Relation#entityColumn属性:存在于@Relation#entity对象对象中的表字段(一般是主键),该表字段被@Relation#parentColumn(一般是外键)关联;
@Relation#associateBy属性:如果当前对象和@Relation#entity对象是多对多关系,则还需要使用当前属性关联;
@Relation#projection属性:@Relation#entity对象的表或视图中提取需要的字段,如果为空,表示提取表或视图中的全部字段。
@Junction注解属性:
@Relation(parentColumn = "playlistId",entity = Song::class,entityColumn = "songId",associateBy = @Junction(value = PlaylistSongXRef::class,parentColumn = "pId",entityColumn = "sId"))val songs: List<Song>--------------------- 分割线:上下是两个不同类------------------@Entity(primaryKeys = {"pId", "sId"})
public class PlaylistSongXRef {val pId: Int,val sId: Int}
@Junction#parentColumn属性:对应的是@Relation#parentColumn字段, 如果@Junction#parentColumn没有设置,那么使用@Relation#parentColumn中的字段;
@Junction#entityColumn属性:对应@Relation#entityColumn字段,如果@Junction#entityColumn没有设置,那么使用@Relation#entityColumn中的属性;
@Junction#value属性:必须使用@Entity 或 @DatabaseView修饰的类,该类表示用于存储当前表主键和受关联表主键;
- 如果是@Entity修饰,表示仙剑一个多对多关系表,那么当前表中的parentColumn字段和entityColumn字段最好创建索引,否则警告。
规则如下:
@Relation#parentColumn的属性值必须存在,而且必须包含在当前表常规字段或当前表的嵌入表常规字段中;
表关系字段类型,如果是集合,那么当前集合只允许是List或Set集合,并且只允许List< T>,List<T extends ?>或Set< T>,Set<T extends ?>;
如果表关系类型是集合,T作为返回类型校验;否则返回类型校验直接校验表关系类型;返回类型是实际类型,e.g.String可以,?或者 T不可以;
@Relation#entity中的属性必须是类或接口,作为entity关系节点;如果当前@Relation#entity属性不存在,使用当前@Relation修饰的节点作为entity关系节点;
- entity关系节点必须使用@Entity或@DatabaseView修饰;
@Relation修饰的有效字段类型,不能存在递归引用。e.g.pojo节点和pojo节点中@Relation修饰的节点类型一致,则表示递归,肯定不被允许;
@Relation#entityColumn必须存在,并且该字段存在于entity关系节点类型中的所有有效字段中;
1.3.3.1 多对多关系对象
如果关系对象是多对多关系,还需要使用@Junction注解,在@Relation#associateBy属性中设置。规则如下:
@Relation#associateBy的属性@Junction,@Junction#value的属性值类型必须是@Entity 或 @DatabaseView修饰;
parentColunm属性:在@Relation#associateBy属性中,如果@Junction#parentColumn存在,使用当前字段作为连接父级表的列属性;否则使用@Relation#parentColunm;
entityColumn属性:在@Relation#associateBy属性中,如果@Junction#entityColumn存在,使用当前字段作为连接实体表的列属性;否则使用@Relation#entityColumn;
parentColunm属性或entityColumn属性校验:
- (1)字段必须存在于@Junction#value属性类型的表常规字段中;
- (2) 如果当前@Junction#value的属性值类型是entity节点(表信息),那么当前表的主键和索引字段应该包含parentColunm属性和entityColumn属性,否则警告-因为会导致全表扫描,影响效率;
- @Relation#projection表示在关系表中获取哪些字段;如果不设置表示获取关系表全部信息;
1.3.4 索引字段
如何使用索引:
@ColumnInfo#index = true,表示当前表常规字段创建索引;
@Entity#indices,表示当前表中创建索引的表字段;
@Entity#inheritSuperIndices = true,并且@Entity修饰的父类也是用了@Entity修饰,其#indices属性集合;
其中,2和3使用的是@Index注解。
@Index注解属性:
索引名称:@Index#name属性值用于表示新建的索引名称;@Index#name属性值不存在,则使用
index_表名_表字段
;@Index#value属性值表示索引字段;
@Index#orders属性值表示表字段在当前索引中的排序;
- 如果当前属性值不为空,那么当前索引的@Index#orders的个数和索引字段个数一定相同;
- @Index#unique属性表示是否唯一索引;默认主键为唯一索引,但是一个表并不一定只有一个唯一索引;当前属性默认是false。
如果表中存在索引,那么索引规则如下::
一个表中新建的索引名称只能出现一次;
嵌入表中最好不要存在使用索引,否则会报警告,表示当前索引无效;
1.3.5 主键字段
使用主键方式有两个:
- @PrimaryKey注解修饰的表字段,一般是表常规字段;
- (1)当前修饰的主键不允许是嵌入表(@Embedded修饰的节点)的常规字段,否则警告,并且无效;
- (2)如果修饰的是表嵌入字段,即@PrimaryKey和@Embedded同时修饰的节点:@PrimaryKey#autoGenerate = false || @Embedded修饰对象的表常规字段有且仅有一个;
- @Entity#primaryKeys中设置;还可以通过entity节点的父entity节点继承过来,即@Entity修饰的节点的父节点也是@Entity修饰,并且该父entity节点存在@Entity#primaryKeys属性;
@PrimaryKey注解属性:
@PrimaryKey#autoGenerate属性值:表示是否允许自动生成当前主键字段,默认是false;
主键使用规则如下:
表主键必须存在;主键有且仅有一个,但是可以由多个表字段组成;
如果@PrimaryKey#autoGenerate = true,那么主键字段不是int类型,必须使用@NonNull修饰,表示不允许null值;
主键默认是txt类型,如果主键是自动生成(@PrimaryKey#autoGenerate= true)的表字段 ,那么当前表字段必须是int类型;
1.3.6 外键字段
只能通过@Entity#foreignKeys中的属性值来设置@ForeignKey外键;
@ForeignKey注解属性和规则如下:
@Entity#foreignKeys属性表示当前表外键;
@ForeignKey#entity属性必须存在,表示当前外键指向的表;
- 必须存在,并且属性值中的对象必须使用@Entity修饰;
@ForeignKey#parentColumns属性表示当前表外键字段指向的外键表字段,必须存在与@ForeignKey#entity对象中;
@ForeignKey#childColumns属性,表示当前表外键字段,该字段指向@ForeignKey#entity对象的表字段(一般是主键);必须存在
- @ForeignKey#parentColumns和 @ForeignKey#childColumns一定是等长;
@ForeignKey#deferred属性,如果为true表示当前外键约束存在于事务中,事务全部结束才会生效;
@ForeignKey#onDelete,@ForeignKey#onUpdate表示外键删除还是更新,有以下几种状态
- (1)默认NO_ACTION,当前外键约束不做任何改动;
- (2)RESTRICT:不允许对当前外键约束进行任何改动,删除或修改操作;
- (3)SET_NULL:父键表对表字段(当前表字段是子键表的外键约束)进行删除或修改操作时,子键表的外键值设置为null;
- (4)SET_DEFAULT:类似于SET_NULL,只不过子键表的外键值设置为默认值;
- (5)CASCADE:父键表对表字段(当前表字段是子键表的外键约束)进行删除或修改操作时,子键表根据进行相应的更改;
- (6)如果不存在以上几种类型范围,则报错;
表外键字段指向外键表字段:该外键表字段要么是主键,要么创建了唯一性索引;否则会报警告;
外键指向的表必须存在于@DatabaseView#entities中;
1.4 其他
1.4.1 @SkipQueryVerification注解
表示是否跳过数据库版本校验。规则如下:
如果@SkipQueryVerification和@Database同时使用,表示当前数据库版本不做校验;
如果@SkipQueryVerification和@DatabaseView,则仅仅表示不对当前@DatabaseView#vlue的sql校验;
同理,如果@SkipQueryVerification和@Insert(@Delete、@Query或@Update)一起使用,不对当前@Insert#value的sql校验;
@RawQuery修饰的方法无论有没有使用@SkipQueryVerification都不会去做当前方法的sql校验;
1.4.2 类型转换
@TypeConverters修饰的注解实现类型转换,转换成表字段支持的类型。
当前表常规字段类型不支持boolean(或Boolean)类型的,但是我们却可以正常使用boolean或Boolean:因为Room系统为我们内部做了类型转换,boolean变量转换成表字段时,boolean = true转换成int = 1;boolean = false转换成int = 0;从表字段中提取数据时,同理,int转换成boolean。
先给个案例:
@Database(entities = News.class)
class Database extends RoomDatabase{xxx;
}
实体类:
@Entity@TypeConverters(ThumbConverter::class)data class News(@PrimaryKeyvar row: String,var title: String = "",var type: Int = 2,val thumb: List<String>?,var content_time: String? = "",var source: String? = "",var hot: Int = 0)
类型转换器:@TypeConverter的两个方法是成对出现的,方法名称可以任意命名,重点在入参和出参类型,必须是需要转换的类型和最终转换后的类型。
class ThumbConverter {//从表字段中提取时转换成list@TypeConverterfun getThumbFromString(value: String):List<String>? {return value.split(",")}//存入表字段时list抓好string@TypeConverterfun storeThumbToString(list: List<String>): String {val str = StringBuilder(list[0])list.forEach {str.append(",").append(it)}return str.toString()}}
哪些情况下可以和@TypeConverters一起使用,实现类型转换:
可以理解为**@TypeConverters可以在任何场合下使用,当然前提条件是必须支持修饰那种类型**。
@TypeConverters#value中的对象我们称之为typeConverters对象。
@TypeConverter修饰的方法我们称之为typeConverter方法。
规则如下:
typeConverters对象必须是一个类;
typeConverters对象中必须存在被@TypeConverter修饰的方法,并且是成对的,一个表示转入,一个表示转出;
typeConverters对象是内部类,除非使用@ProvidedTypeConverter修饰,否则必须使用static修饰;
typeConverters对象除非使用@ProvidedTypeConverter修饰,否则支持一下条件中的至少一个条件:
- (1)typeConverters对象是
object
或companion object
kotlin类型; - (2)typeConverter方法必须全部static修饰;
- (3)typeConverters对象构造函数为空
- (4)typeConverters对象构造函数存在,但是参数为空;
typeConverter方法必须public修饰;
typeConverter方法返回类型不允许void(error ,none)类型;
typeConverter方法返回类型如果是泛型,必须是实体类型(如List),不允许出现List< T>或List<?>类型;
typeConverter方法参数必须有且仅有一个;
typeConverter方法参数类型如果是泛型,必须是实体类型(如List),不允许出现List< T>或List<?>类型;
@TypeConverters#value中的typeConverters对象可以有多个,这些对象的所有typeConverter方法不允许出现方法返回类型和方法参数类型都一致的情况;
typeConverters对象中只有@TypeConverter修饰的方法有效,其他方法无任何意义,也不会报错。
还有一种情况(本不想说的,估计用的不大,或者不能用,可以验证一下),已上面的案例为例:@TypeConverters(ThumbConverter::class)在database节点上修饰,在entity节点上没有使用,好像大概可能也是可以的。
续
感觉篇幅太大,所以额外在写文章继续dao操作数据库。
从架构设计角度分析AAC源码-Room注解使用大全(基于2.4版本源码解析)(一)相关推荐
- 代练工作室php源码,PHP开发的代练系统V2.0版本源码 附带搭建和对接支付视频
PHP开发的代练系统V2.0版本源码 附带搭建和对接支付视频 1/ 修改DB数据库MYSQL连接配置文件 /Public_Menglenet/A/Common/Conf/Config.php 内的数据 ...
- 无人机飞控 ardupilot-4.0.7 版本源码总体框架
无人机飞控 ardupilot-4.0.7 版本源码总体框架 无人机飞控 ardupilot-4.0.7 版本源码总体框架 基本结构 最外层文件 无人机飞控 ardupilot-4.0.7 版本源码总 ...
- 下载附带.php,PHP开发的优客365网址导航商业精华版1.1.6版本源码带WAP手机版附带三款模板和四款插件-资源下载随便下源码网...
PHP开发的优客365网址导航商业精华版1.1.6版本源码,带WAP手机版,附带三款模板和四款插件 p优客365网站分类导航系统是个跨平台的开源软件,基于PHPMYSQL开发构建的开源网站分类目录管理 ...
- 小程序源码:社群微群人脉系统小程序版本源码下载带流量主功能实现广告效益
现在因为小编在实现新版本的功能添加与更新 所以小编就把这一款开源分享给大家吧! 分享出来考虑到大家服务器等等效益所以小编就把后台给砍掉了 所以大家就直接前端上传到微信开发者工具即可使用 本款小程序群二 ...
- 人生重开模拟器微信小程序源码下载开启不一样的人生体验+网站版本源码双版本
这是一款人生重开模拟器微信小程序源码 让你的人生开启不一样的变化 不知道各位玩家有没有被最近超火的一款名为<人生重开模拟器>小游戏刷屏呢?想必不少玩家玩过了各种各样的模拟器,有的可以模拟医 ...
- 一款好用的网络骗子举报系统无加密版本源码
正文: 分享一款好用的网络骗子举报系统无加密版本源码,源码特点如下: 1,源码可控,代码无后门,可放心使用源代码注释详细,便于阅读,提供丰富的配置接口,易于扩展. 2,功能完善,包含管理系统常用的基础 ...
- 玖逸云黑免费无加密版本源码-亲测可用
玖逸云黑无加密版本优势,拥有多年管理系统产品开发经验 1,源码可控,代码无后门,可放心使用源代码注释详细,便于阅读,提供丰富的配置接口,易于扩展. 2,功能完善,包含管理系统常用的基础功能,提供丰富的 ...
- CYQ.Data 数据框架 加快开源速度 发布V1.5.5版本源码
前言: 上周发布:秋色园QBlog V2.5 后台管理系统源码发布下载 之后,截至今日,后台统计的下载次数是:1321. 在此感谢大家的支持与关注. 秋色园QBlog 后台管理系统是 CYQ.Data ...
- vue2.6.11版本源码运行报错问题处理
vue2.6.11版本源码运行报错问题处理 1.源码下载 git clone http://github.com/vuejs/vue.git 2.安装npm依赖包 npm install 3.运行报错 ...
- 2022最新彩虹易支付系统二开版本源码/新增推广返利模式+工单系统
源码介绍 2022最新彩虹易支付系统二开版本源码/新增推广返利模式+工单系统 系统环境要求:PHP>=7.1 + MySQL5.6 更新日志: 2022/10/26 1.新增用户登陆邮箱提醒(防 ...
最新文章
- axis WebServices 完美调用天气预报,查询、显示 代码!
- vue 发送ajax请求
- 电子计算机可直接执行的指令机器内部是以,电子计算机可直接执行的指令在机器内部是以( )表示....
- -bash: wget: 未找到命令_18个堪称神器的命令行工具,高效运维必备
- 适用所有服务器的全站301重定向跳转教程
- 【树】判断给定森林中有多少棵树(简单做法)
- 基于EasyNetQ的RabbitMQ封装类
- setuptools find_packages
- mysql 存储过程 脚本_mysql利用存储过程插入大量数据脚本
- python : sha256 、ripemd160
- 一种考虑时空关联的深度学习短时交通流预测方法
- fluent的udf在windows可以编译 linux错误,fluent中udf环境变量设置,简单可行!已试过!...
- checksum计算方法
- Error while sending STMT_PREPARE packet. PID=29294
- 紫光收购武汉新芯后长江存储成立 赵伟国任董事长
- 微信公众号抓取研究----使用xposed程序hook
- java基本数据类型Char
- html中css在哪里写,css可以在html里面写吗
- 英语语法---四种句子类型的介绍
- flutter如何让row中的子组件高度保持一致