关于 Room,网上优秀的文章太多了。本文我只从自己的角度介绍 Room 使用,相信对你也够用了的。
Room Google 文档:https://developer.android.google.cn/topic/libraries/architecture/room
一、环境配置:
// room 配置
implementation "android.arch.persistence.room:runtime:1.1.1"
implementation "android.arch.persistence.room:rxjava2:1.1.1"
annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
如果是 androidx,则参考官网的配置。
二、Room 结构简介:
Room 组件的三个核心部分,分别是:
1、Entity 数据实体类,同时映射为数据库中的表结构。
2、Dao 数据库表的增删改查操作类。
3、Database SqLite 数据库对象获取和管理类。
三、Entity 注解简介:
Entity 是注解。使用 Entity 标记的类,将会被映射为数据库中的表。以话题赛事提醒需求为例说明:
@Entity(tableName = "topic_match_table",
primaryKeys = {"topic_id", "match_id"},
indices = {
@Index(value = {"topic_id"}),
@Index(value = {"topic_id", "match_id"})
})
@Keep
public class MatchEntity implements Parcelable {
public MatchEntity() {
}
@Ignore
public MatchEntity(int matchId) {
this.mMatchId = matchId;
}
@Ignore
public MatchEntity(String topicId, int matchId, String teamA, String teamB, long timeStart) {
this.mTopicId = topicId;
this.mMatchId = matchId;
this.mTeamA = teamA;
this.mTeamB = teamB;
this.mTimeStart = timeStart;
}
// 话题 id
@ColumnInfo(name = "topic_id")
@NonNull
public String mTopicId;
// 赛事 id
@ColumnInfo(name = "match_id")
@NonNull
public int mMatchId;
// 赛队 A
@ColumnInfo(name = "team_a")
public String mTeamA;
// 赛队 B
@ColumnInfo(name = "team_b")
public String mTeamB;
// 闹钟开始时间
@ColumnInfo(name = "time_start")
public long mTimeStart;
@Ignore
public PendingIntent mPendingIntent;
// 参考 AlarmManager.RTC_WAKEUP
// ELAPSED 开头的代表系统运行逝去的时间,RTC 开头的是世界时钟
// 以WAKEUP结尾的类型能够唤醒设备
// public static final int RTC_WAKEUP = 0;
// public static final int RTC = 1;
// public static final int ELAPSED_REALTIME_WAKEUP = 2;
// public static final int ELAPSED_REALTIME = 3;
// 闹钟类型
@Ignore
public int mAlarmManagerType = AlarmManager.RTC_WAKEUP;
@Override
public String toString() {
String name = MatchEntity.class.getCanonicalName();
if (name == null) {
return super.toString();
}
String timeString = SimpleDateFormat.getDateTimeInstance().format(new Date(mTimeStart));
return name + " -> mTopicId = " +
mTopicId +
" mMatchId = " +
mMatchId +
" mTeamA = " +
mTeamA +
" mTeamB = " +
mTeamB +
" mTimeStart = " +
timeString;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.mTopicId);
dest.writeInt(this.mMatchId);
dest.writeString(this.mTeamA);
dest.writeString(this.mTeamB);
dest.writeLong(this.mTimeStart);
dest.writeParcelable(this.mPendingIntent, flags);
dest.writeInt(this.mAlarmManagerType);
}
protected MatchEntity(Parcel in) {
this.mTopicId = in.readString();
this.mMatchId = in.readInt();
this.mTeamA = in.readString();
this.mTeamB = in.readString();
this.mTimeStart = in.readLong();
this.mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader());
this.mAlarmManagerType = in.readInt();
}
public static final Parcelable.Creator<MatchEntity> CREATOR = new Parcelable.Creator<MatchEntity>() {
@Override
public MatchEntity createFromParcel(Parcel source) {
return new MatchEntity(source);
}
@Override
public MatchEntity[] newArray(int size) {
return new MatchEntity[size];
}
};
}
1、类声明处使用了 @Entity 注解。tableName 属性表示 MatchEntity 类映射到数据中的表名为 topic_match_table。primaryKeys 属性表示创建了一个联合主键。indices 属性值表明创建了 2 个索引。
2、属性和构造函数上使用了 @Ignore 注解。除了无参的构造函数外,其他所有的构造函数都需要添加此注解。不想被映射到数据库表字段的属性需要添加此注解。
3、在属性上使用了 @ColumnInfo 注解,表示此属性映射到数据库表的字段名。如果不添加此注解,则类属性名和表字段名相同。
4、设置为主键的属性,需要添加 @NonNull 注解。
5、也可以直接在某属性上使用 @PrimaryKey 注解声明主键。
以上只是 Entity 部分内容,掌握了这么多基本够用。
四、Dao 注解简介:
使用 Dao 注解标注的接口,承载着对 Entity 增删改查的使命。
@Dao
public interface MatchDao {
@Query("SELECT match_id FROM topic_match_table WHERE topic_id = :topicId")
int[] getTopicMatchesId(String topicId);
@Query("SELECT * FROM topic_match_table")
List<MatchEntity> getAllMatches();
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertMatch(MatchEntity... matchEntities);
@Delete
void deleteMatch(MatchEntity... matchEntities);
@Query("DELETE FROM topic_match_table WHERE topic_id = :topicId AND match_id = :matchId")
void deleteMatchById(String topicId, int matchId);
}
1、@Dao 标注在接口上,忘记是否可以是抽象类了。
2、对数据库的增删改查四种操作,分别对应 @Insert / @Delete / @Update / @Query 4 个注解。
3、灵活运用。比喻删除操作也可以使用 @query 注解:@Query("DELETE FROM topic_match_table WHERE topic_id = :topicId AND match_id = :matchId")
4、@Insert 注解的 onConflict 参数含义是:当添加发生冲突时,直接替换旧数据。
5、更多信息可以参考 Room 组件注解的声明说明。
五、Database 注解简介:
Database 注解,标注配置一些数据库的信息。
@Database(entities = {MatchEntity.class}, version = MatchDatabase.DB_VERSION, exportSchema = false)
public abstract class MatchDatabase extends RoomDatabase {
// you need update this version value when you update database structure
public static final int DB_VERSION = 1;
public static final String DB_NAME = "topic_match.db";
public abstract MatchDao getMatchDao();
}
1、注意,自定义抽象类 MatchDatabase 继承RoomDatabase 类。
2、@Database 注解标注在 MatchDatabase 抽象类上,表示此数据库的名称、数据库中有哪些表、是否导出历史数据和表结构的 json 数据。
3、MatchDatabase 需要提供一个公共的抽象的方法,返回某 Entity 的操作类,比喻 MatchDao。
六、Room 使用简介:
public class MatchRoomHelper {
private static MatchDatabase MATCH_DATABASE;
private static MatchRoomHelper INSTANCE;
private MatchRoomHelper(Context applicationContext) {
MATCH_DATABASE = Room.databaseBuilder(applicationContext, MatchDatabase.class, MatchDatabase.DB_NAME)
.allowMainThreadQueries() // 允许在主线程执行数据库操作
.build();
}
public synchronized static MatchRoomHelper getInstance(Context applicationContext) {
if (INSTANCE == null) {
INSTANCE = new MatchRoomHelper(applicationContext);
}
return INSTANCE;
}
public List<MatchEntity> getAllMatches() {
return MATCH_DATABASE.getMatchDao().getAllMatches();
}
public int[] getTopicMatchesId(String topicId) {
return MATCH_DATABASE.getMatchDao().getTopicMatchesId(topicId);
}
public synchronized void insertMatch(MatchEntity... matchEntities) {
MATCH_DATABASE.getMatchDao().insertMatch(matchEntities);
}
public synchronized void deleteMatch(MatchEntity... matchEntities) {
MATCH_DATABASE.getMatchDao().deleteMatch(matchEntities);
}
}
1、MatchDatabase 是实际的数据库配置承载类,可以使用 Room.databaseBuilder()创建数据库对象。参考 MatchRoomHelper 构造函数代码。
2、注意 allowMainThreadQueries() 配置,表示是否允许在主线程执行数据库操作。默认是不允许的,如果不允许,则在 UI 线程执行数据库操作会崩溃。
3、MatchDatabase 数据库对象不建议重复创建,或使用单例模式?!
4、通过 MatchRoomHelper 获取单例的 MatchDatabase 数据库对象,再获取 MatchDao 对象,就可以对对应的 Entity 进行增删改查操作了。