Android架構(gòu)組件Room的使用詳解
Room其實(shí)就是一個(gè)orm,抽象了SQLite的使用,但是它作為Android的親兒子orm,并且原生支持LiveData和Rxjava嵌套使用,學(xué)習(xí)一下還是不錯(cuò)的。
Room有3個(gè)主要組件
- Database :數(shù)據(jù)庫(kù)
- Entity : 代表數(shù)據(jù)庫(kù)一個(gè)表結(jié)構(gòu)
- Dao : 包含訪問(wèn)數(shù)據(jù)庫(kù)的方法
簡(jiǎn)單使用
添加Google Maven倉(cāng)庫(kù)
allprojects {
repositories {
jcenter()
google()
}
}
添加依賴
dependencies {
// Room
implementation "android.arch.persistence.room:runtime:1.0.0"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
}
定義數(shù)據(jù)表實(shí)體類
班級(jí)表
@Entity(tableName = "tb_class")
public class ClassEntity {
@PrimaryKey
private long id;
}
學(xué)生表
//指示數(shù)據(jù)表實(shí)體類
@Entity(tableName = "tb_student",//定義表名
indices = @Index(value = {"name", "sex"}, unique = true),//定義索引
foreignKeys = {@ForeignKey(entity = ClassEntity.class,
parentColumns = "id",
childColumns = "class_id")})//定義外鍵
public class StudentEntity {
@PrimaryKey //定義主鍵
private long id;
@ColumnInfo(name = "name")//定義數(shù)據(jù)表中的字段名
private String name;
@ColumnInfo(name = "sex")
private int sex;
@Ignore//指示Room需要忽略的字段或方法
private String ignoreText;
@ColumnInfo(name = "class_id")
private String class_id;
//setter and getter
}
Entity注解可選參數(shù)
public @interface Entity {
//定義表名
String tableName() default "";
//定義索引
Index[] indices() default {};
//設(shè)為true則父類的索引會(huì)自動(dòng)被當(dāng)前類繼承
boolean inheritSuperIndices() default false;
//定義主鍵
String[] primaryKeys() default {};
//定義外鍵
ForeignKey[] foreignKeys() default {};
}
Index索引注解可選參數(shù)
public @interface Index {
//定義需要添加索引的字段
String[] value();
//定義索引的名稱
String name() default "";
//true-設(shè)置唯一鍵,標(biāo)識(shí)value數(shù)組中的索引字段必須是唯一的,不可重復(fù)
boolean unique() default false;
}
ForeignKey外鍵注解可選參數(shù)
public @interface ForeignKey {
//引用外鍵的表的實(shí)體
Class entity();
//要引用的外鍵列
String[] parentColumns();
//要關(guān)聯(lián)的列
String[] childColumns();
//當(dāng)父類實(shí)體(關(guān)聯(lián)的外鍵表)從數(shù)據(jù)庫(kù)中刪除時(shí)執(zhí)行的操作
@Action int onDelete() default NO_ACTION;
//當(dāng)父類實(shí)體(關(guān)聯(lián)的外鍵表)更新時(shí)執(zhí)行的操作
@Action int onUpdate() default NO_ACTION;
//在事務(wù)完成之前,是否應(yīng)該推遲外鍵約束
boolean deferred() default false;
//給onDelete,onUpdate定義的操作
int NO_ACTION = 1;
int RESTRICT = 2;
int SET_NULL = 3;
int SET_DEFAULT = 4;
int CASCADE = 5;
@IntDef({NO_ACTION, RESTRICT, SET_NULL, SET_DEFAULT, CASCADE})
@interface Action {
}
}
定義Dao類
@Dao
public interface StudentDao {
@Query("SELECT * FROM StudentEntity")
List<StudentEntity> getAll();
@Query("SELECT * FROM StudentEntity WHERE id IN (:ids)")
List<StudentEntity> getAllByIds(long[] ids);
@Insert
void insert(StudentEntity... entities);
@Delete
void delete(StudentEntity entity);
@Update
void update(StudentEntity entity);
}
@insert, @Update都可以執(zhí)行事務(wù)操作,定義在OnConflictStrategy注解類中
public @interface Insert {
//定義處理沖突的操作
@OnConflictStrategy
int onConflict() default OnConflictStrategy.ABORT;
}
public @interface OnConflictStrategy {
//策略沖突就替換舊數(shù)據(jù)
int REPLACE = 1;
//策略沖突就回滾事務(wù)
int ROLLBACK = 2;
//策略沖突就退出事務(wù)
int ABORT = 3;
//策略沖突就使事務(wù)失敗
int FAIL = 4;
//忽略沖突
int IGNORE = 5;
}
定義數(shù)據(jù)庫(kù)
@Database(entities = {StudentEntity.class}, version = 1)
public abstract class RoomDemoDatabase extends RoomDatabase {
public abstract StudentDao studentDao();
}
生成數(shù)據(jù)庫(kù)實(shí)例
RoomDemoDatabase database = Room.databaseBuilder(getApplicationContext(), RoomDemoDatabase.class, "database_name")
.build();
生成數(shù)據(jù)庫(kù)實(shí)例的其他操作
Room.databaseBuilder(getApplicationContext(),
RoomDemoDatabase.class, "database_name")
.addCallback(new RoomDatabase.Callback() {
//第一次創(chuàng)建數(shù)據(jù)庫(kù)時(shí)調(diào)用,但是在創(chuàng)建所有表之后調(diào)用的
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
}
//當(dāng)數(shù)據(jù)庫(kù)被打開(kāi)時(shí)調(diào)用
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
})
.allowMainThreadQueries()//允許在主線程查詢數(shù)據(jù)
.addMigrations()//遷移數(shù)據(jù)庫(kù)使用,下面會(huì)單獨(dú)拿出來(lái)講
.fallbackToDestructiveMigration()//遷移數(shù)據(jù)庫(kù)如果發(fā)生錯(cuò)誤,將會(huì)重新創(chuàng)建數(shù)據(jù)庫(kù),而不是發(fā)生崩潰
.build();
數(shù)據(jù)庫(kù)遷移(升級(jí))
Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, "
+ "`name` TEXT, PRIMARY KEY(`id`))");
}
};
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE Book "
+ " ADD COLUMN pub_year INTEGER");
}
};
創(chuàng)建嵌套對(duì)象
有時(shí),您希望將一個(gè)實(shí)體或普通的以前的Java對(duì)象(POJO)作為數(shù)據(jù)庫(kù)邏輯中的一個(gè)完整的整體來(lái)表示,即使該對(duì)象包含幾個(gè)字段。在這些情況下,您可以使用@Embedded來(lái)表示一個(gè)對(duì)象,您希望將其分解為表中的子字段。然后可以像對(duì)其他單個(gè)列一樣查詢嵌入式字段
class Address {
public String street;
public String state;
public String city;
@ColumnInfo(name = "post_code")
public int postCode;
}
@Entity
class User {
@PrimaryKey
public int id;
public String firstName;
@Embedded
public Address address;
}
這樣user表中的字段就包含了 id , firstName , street , state , city , 和 post_code
注意 :嵌入式字段還可以包含其他嵌入式字段
如果一個(gè)實(shí)體具有相同類型的多個(gè)內(nèi)嵌字段,則可以通過(guò)設(shè)置前綴屬性(prefix)使每個(gè)列保持惟一。然后將所提供的值添加到嵌入對(duì)象中每個(gè)列名的開(kāi)頭
@Embedded(prefix = "foo_") Coordinates coordinates;
和 LiveData 一起使用
添加依賴
// ReactiveStreams support for LiveData implementation "android.arch.lifecycle:reactivestreams:1.0.0"
修改返回類型
@Dao
public interface MyDao {
@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
public LiveData<List<User>> loadUsersFromRegionsSync(List<String> regions);
}
和RxJava一起使用
添加依賴
// RxJava support for Room implementation "android.arch.persistence.room:rxjava2:1.0.0"
修改返回類型
@Dao
public interface MyDao {
@Query("SELECT * from user where id = :id LIMIT 1")
public Flowable<User> loadUserById(int id);
}
直接游標(biāo)訪問(wèn)
@Dao
public interface MyDao {
@Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
public Cursor loadRawUsersOlderThan(int minAge);
}
類型轉(zhuǎn)換
定義轉(zhuǎn)換類,@TypeConverter注解定義轉(zhuǎn)換的方法
public class Converters {
@TypeConverter
public static Date fromTimestamp(Long value) {
return value == null ? null : new Date(value);
}
@TypeConverter
public static Long dateToTimestamp(Date date) {
return date == null ? null : date.getTime();
}
}
@TypeConverters注解,告知數(shù)據(jù)庫(kù)要依賴哪些轉(zhuǎn)換類
@Database(entities = {User.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
使用這些轉(zhuǎn)換器,您可以在其他查詢中使用您的自定義類型,正如您將使用基本類型一樣,如下代碼所示
@Entity
public class User {
...
private Date birthday;
}
@Dao
public interface UserDao {
...
@Query("SELECT * FROM user WHERE birthday BETWEEN :from AND :to")
List<User> findUsersBornBetweenDates(Date from, Date to);
}
輸出模式
在編譯時(shí),將數(shù)據(jù)庫(kù)的模式信息導(dǎo)出到JSON文件中,這樣可有利于我們更好的調(diào)試和排錯(cuò)
build.gradle
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
}
您應(yīng)該將導(dǎo)出的JSON文件(表示數(shù)據(jù)庫(kù)的模式歷史記錄)存儲(chǔ)在您的版本控制系統(tǒng)中,因?yàn)樗试S為測(cè)試目的創(chuàng)建您的數(shù)據(jù)庫(kù)的舊版本
總結(jié)
以上所述是小編給大家介紹的Android架構(gòu)組件Room的使用詳解,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- Android Jetpack架構(gòu)組件Lifecycle詳解
- Android Jetpack架構(gòu)組件 ViewModel詳解
- Android 生命周期架構(gòu)組件使用方法
- Android架構(gòu)組件Room指南
- Android-ViewModel和LiveData使用詳解
- Android LiveData使用需要注意的地方
- Android mvvm之LiveData原理案例詳解
- Android 基于MediatorLiveData實(shí)現(xiàn)紅點(diǎn)的統(tǒng)一管理
- 詳解Android JetPack之LiveData的工作原理
- Android架構(gòu)組件LiveData使用詳解
相關(guān)文章
Android開(kāi)發(fā)手冊(cè)shape屬性和子屬性使用說(shuō)明
這篇文章主要為大家介紹了Android開(kāi)發(fā)手冊(cè)shape屬性和子屬性使用說(shuō)明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
深入理解TextView實(shí)現(xiàn)Rich Text--在同一個(gè)TextView設(shè)置不同字體風(fēng)格
本篇文章是對(duì)Android中在同一個(gè)TextView中設(shè)置不同的字體風(fēng)格進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Android 中按home鍵和跳轉(zhuǎn)到主界面的實(shí)例代碼
本文通過(guò)實(shí)例代碼給大家分享Android 中按home鍵和跳轉(zhuǎn)到主界面的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-04-04
android @override 報(bào)錯(cuò)解決方案
android @override 報(bào)錯(cuò):就是說(shuō)Java 1.5的編譯器默認(rèn)對(duì)父類的方法進(jìn)行覆蓋,采用@Override進(jìn)行說(shuō)明;但1.6已經(jīng)擴(kuò)展到對(duì)接口的方法;所以如果還是以Java 1.5的編譯器來(lái)編譯的話,會(huì)出現(xiàn)錯(cuò)誤2012-12-12
Android自定義view實(shí)現(xiàn)日歷打卡簽到
這篇文章主要為大家詳細(xì)介紹了Android自定義view實(shí)現(xiàn)日歷打卡簽到,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
Android實(shí)現(xiàn)關(guān)機(jī)與重啟的幾種方式(推薦)
這篇文章主要介紹了Android實(shí)現(xiàn)關(guān)機(jī)與重啟的幾種方式(推薦)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Android快速實(shí)現(xiàn)發(fā)送郵件實(shí)例
本篇文章主要介紹了Android快速實(shí)現(xiàn)發(fā)送郵件實(shí)例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04
Android中EditText的drawableRight屬性設(shè)置點(diǎn)擊事件
這篇文章主要介紹了Android中EditText的drawableRight屬性的圖片設(shè)置點(diǎn)擊事件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
Android?補(bǔ)間動(dòng)畫及組合AnimationSet常用方法詳解
這篇文章主要為大家介紹了Android?補(bǔ)間動(dòng)畫及組合AnimationSet常用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11

