Android架構組件Room的使用

Android架構組件Room的使用

Room其實就是一個orm,抽象了SQLite的使用,可是它做爲Android的親兒子orm,而且原生支持LiveData和Rxjava嵌套使用,學習一下仍是不錯的。html

Room有3個主要組件java

  • Database :數據庫
  • Entity : 表明數據庫一個表結構
  • Dao : 包含訪問數據庫的方法

簡單使用

添加Google Maven倉庫

allprojects {
    repositories {
        jcenter()
        google()
    }
}
複製代碼

添加依賴

dependencies {
    // Room
   implementation "android.arch.persistence.room:runtime:1.0.0"
   annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
}
複製代碼

定義數據表實體類

班級表react

@Entity(tableName = "tb_class")
public class ClassEntity {

    @PrimaryKey
    private long id;
}
複製代碼

學生表android

//指示數據表實體類
@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")//定義數據表中的字段名
    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註解可選參數

public @interface Entity {
	//定義表名
    String tableName() default "";
	//定義索引
    Index[] indices() default {};
	//設爲true則父類的索引會自動被當前類繼承
    boolean inheritSuperIndices() default false;
	//定義主鍵
    String[] primaryKeys() default {};
	//定義外鍵
    ForeignKey[] foreignKeys() default {};
}
複製代碼

Index索引註解可選參數

public @interface Index {
  //定義須要添加索引的字段
  String[] value();
  //定義索引的名稱
  String name() default "";
  //true-設置惟一鍵,標識value數組中的索引字段必須是惟一的,不可重複
  boolean unique() default false;
}
複製代碼

ForeignKey外鍵註解可選參數

public @interface ForeignKey {
  //引用外鍵的表的實體
  Class entity();
  //要引用的外鍵列
  String[] parentColumns();
  //要關聯的列
  String[] childColumns();
  //當父類實體(關聯的外鍵表)從數據庫中刪除時執行的操做
  @Action int onDelete() default NO_ACTION;
  //當父類實體(關聯的外鍵表)更新時執行的操做
  @Action int onUpdate() default NO_ACTION;
  //在事務完成以前,是否應該推遲外鍵約束
  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均可以執行事務操做,定義在OnConflictStrategy註解類中數據庫

public @interface Insert {
   //定義處理衝突的操做
    @OnConflictStrategy
    int onConflict() default OnConflictStrategy.ABORT;
}
複製代碼
public @interface OnConflictStrategy {
    //策略衝突就替換舊數據
    int REPLACE = 1;
    //策略衝突就回滾事務
    int ROLLBACK = 2;
  	//策略衝突就退出事務
    int ABORT = 3;
   	//策略衝突就使事務失敗 
    int FAIL = 4;
    //忽略衝突
    int IGNORE = 5;
}
複製代碼

定義數據庫

@Database(entities = {StudentEntity.class}, version = 1)
public abstract class RoomDemoDatabase extends RoomDatabase {

    public abstract StudentDao studentDao();
}
複製代碼

生成數據庫實例

RoomDemoDatabase database = Room.databaseBuilder(getApplicationContext(),
                RoomDemoDatabase.class, "database_name")
                .build();
複製代碼

生成數據庫實例的其餘操做數組

Room.databaseBuilder(getApplicationContext(),
                        RoomDemoDatabase.class, "database_name")
                        .addCallback(new RoomDatabase.Callback() {
                            //第一次建立數據庫時調用,可是在建立全部表以後調用的
                            @Override
                            public void onCreate(@NonNull SupportSQLiteDatabase db) {
                                super.onCreate(db);
                            }

                            //當數據庫被打開時調用
                            @Override
                            public void onOpen(@NonNull SupportSQLiteDatabase db) {
                                super.onOpen(db);
                            }
                        })
                        .allowMainThreadQueries()//容許在主線程查詢數據
                        .addMigrations()//遷移數據庫使用,下面會單獨拿出來說
                        .fallbackToDestructiveMigration()//遷移數據庫若是發生錯誤,將會從新建立數據庫,而不是發生崩潰
                        .build();
複製代碼

數據庫遷移(升級)

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");
    }
};
複製代碼

建立嵌套對象

有時,您但願將一個實體或普通的之前的Java對象(POJO)做爲數據庫邏輯中的一個完整的總體來表示,即便該對象包含幾個字段。在這些狀況下,您可使用@Embedded來表示一個對象,您但願將其分解爲表中的子字段。而後能夠像對其餘單個列同樣查詢嵌入式字段架構

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_codeide

注意:嵌入式字段還能夠包含其餘嵌入式字段post

若是一個實體具備相同類型的多個內嵌字段,則能夠經過設置前綴屬性(prefix)使每一個列保持唯一。而後將所提供的值添加到嵌入對象中每一個列名的開頭學習

 @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);
}
複製代碼

直接遊標訪問

@Dao
public interface MyDao {
    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
    public Cursor loadRawUsersOlderThan(int minAge);
}
複製代碼

類型轉換

定義轉換類,@TypeConverter註解定義轉換的方法

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註解,告知數據庫要依賴哪些轉換類

@Database(entities = {User.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}
複製代碼

使用這些轉換器,您能夠在其餘查詢中使用您的自定義類型,正如您將使用基本類型同樣,以下代碼所示

@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);
}
複製代碼

輸出模式

在編譯時,將數據庫的模式信息導出到JSON文件中,這樣可有利於咱們更好的調試和排錯

build.gradle

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation":
                             "$projectDir/schemas".toString()]
            }
        }
    }
}
複製代碼

您應該將導出的JSON文件(表示數據庫的模式歷史記錄)存儲在您的版本控制系統中,由於它容許爲測試目的建立您的數據庫的舊版本

相關文章
相關標籤/搜索