Android官方ORM Room介绍

基本使用

  1. 通过实体类和注解定义表数据:
Entitypublic class User {    @PrimaryKey    public int uid;        @ColumnInfo(name = "first_name")    public String firstName;        @ColumnInfo(name = "last_name")    public String lastName;}
  1. 创建具体操作的Dao接口类:
@Daopublic interface UserDao {    @Query("SELECT * FROM user")    List getAll();    @Query("SELECT * FROM user WHERE uid IN (:userIds)")    List loadAllByIds(int[] userIds);    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +           "last_name LIKE :last LIMIT 1")    User findByName(String first, String last);    @Insert    void insertAll(User... users);    @Delete    void delete(User user);}
  1. 定义继承自RoomDatabase的数据库类,在这个类中定义创建Dao类的接口,是抽象类,Room将在编译时生成具体的实现类:
@Database(entities = {User.class}, version = 1)public abstract class AppDatabase extends RoomDatabase {    public abstract UserDao userDao();}
  1. 在代码中使用:
//创建db对象AppDatabase db = Room.databaseBuilder(getApplicationContext(),        AppDatabase.class, "database-name").build();//通过在AppDatabase中定义的接口方法获取Dao对象UserDao userdao = db.userDao();//调用Dao中对应方法执行操作userDao.getAll();

数据定义

在Room中,每个表关联一个使用@Entity注解的实体类,表中的列关联到实体类的字段,表的列的属性通过实体类中注解来实现:

@Entitypublic class User {    @PrimaryKey    public int id;    public String firstName;    public String lastName;}

需要在@Database注解entities属性中声明实体类,Room会在编译时自动生成创建表的代码,并在初始化时创建表:

@Database(entities = {User.class}, version = 1)public abstract class AppDatabase extends RoomDatabase {    public abstract UserDao userDao();}

 

  1. 主键
    a. 唯一主键;如上面的代码示例,通过在实体字段上添加@PrimaryKey可以声明该列为主键,@PrimaryKey 注解还包含autoGenerate属性,可以声明主键自动生成如:

    @PrimaryKey(autoGenerate = true)public int id;

    b. 联合主键;当要定义联合主键时可以使用@Entity的属性primaryKeys,如:

    @Entity(primaryKeys = {"firstName", "lastName"}) public class User {     public String firstName;     public String lastName; }

     

  2. 忽略实体字段;一般情况下,实体中所有字段都会在表中创建一个列,当要某些字段不需要创建列时,可以通过添加注解@Ignore将其忽略,如:

    @Entitypublic class User {    @PrimaryKey    public int id;    public String firstName;    public String lastName;    @Ignore    Bitmap picture;}

    也可以通过@Entity的属性ignoredColumns 来将其忽略,如:

    @Entity(ignoredColumns = "picture")public class RemoteUser extends User {    @PrimaryKey    public int id;    public boolean hasVpn;}

     

  3. 查询优化;
    a. 索引;在Room中通过@Entity 的属性indices来建立索引,如:

    @Entity(indices = {@Index("name"),        @Index(value = {"last_name", "address"})})public class User {    @PrimaryKey    public int id;    public String firstName;    public String address;    @ColumnInfo(name = "last_name")    public String lastName;    @Ignore    Bitmap picture;}

    b. 全文检索;SQLite3内置了全文检索的扩展模块——FTS,通过主键@FTS3、@FTS4分别启用基于FTS3和FTS4;如:

    @Fts4@Entity(tableName = "users")public class User {    // Specifying a primary key for an FTS-table-backed entity is optional, but    // if you include one, it must use this type and column name.    @PrimaryKey    @ColumnInfo(name = "rowid")    public int id;    @ColumnInfo(name = "first_name")    public String firstName;}

     

  4. 嵌套对象;有时候,一个表中的几个列在应用逻辑上更适合组合成一个实体,但是为这几个字段单独建表又感觉没必要,Room提供了@Embedded注解来解决这种情况:

    public class Address {    public String street;    public String state;    public String city;    @ColumnInfo(name = "post_code")    public int postCode;}@Entitypublic class User {    @PrimaryKey    public int id;    public String firstName;    @Embedded    public Address address;}

    在上面例子中,会建立一个包含id、firstName、street、city、state、postCode的User表,而在在查询时street、city、state、postCode会自动组合成Address对象,反之亦然。
     

  5. 视图;通过注解@DatabaseView可以创建视图,如:

    @DatabaseView("SELECT user.id, user.name, user.departmentId," +            "department.name AS departmentName FROM user " +            "INNER JOIN department ON user.departmentId = department.id")public class UserDetail {    public long id;    public String name;    public long departmentId;    public String departmentName;}

    同时,要在@Database中views属性中添加:

    @Database(entities = {User.class}, views = {UserDetail.class}, version = 1)public abstract class AppDatabase extends RoomDatabase {   public abstract UserDao userDao();}

数据操作

在Room框架中,我们使用DAOs(data access objects)来对数据库中的数据进行操作。可以通过@Dao注解来声明一个Dao类的接口或者抽象类,每个操作对应一个抽象方法,注解@Insert、@Delete、@Update、@Query分别对应增删改查:

@Daopublic interface UserDao {    @Insert    void insertAll(User... users);    @Update    public void updateUsers(User... users);    @Delete    void delete(User user);    @Query("SELECT * FROM user")    List getAll();}

具体实现类会在编译时自动生成,使用时通过在Database类中定义的工厂方法获取:

@Database(entities = {User.class}, version = 1)public abstract class AppDatabase extends RoomDatabase {    public abstract UserDao userDao();}

 

  1. 多种方法模板;对于不同的应用场景,Room提供了不同类型的方法:
    @Daopublic interface MyDao {    @Insert(onConflict = OnConflictStrategy.REPLACE)    public void insertUsers(User... users);    @Insert    public void insertBothUsers(User user1, User user2);    @Insert    public void insertUsersAndFriends(User user, List friends);}
    每个方法都可以设置返回值,如果只操作一个数据(只有一个传入参数),则返回一个long型的数据,也就是被操作数据的rowID,如果操作一组数据则返回这一组数据的rowID,返回值应该long[] 或者 List< Long >。
     
  2. 查询参数绑定;Room可以通过:[参数名]的方式将参数注入到SQL查询语句中:
    @Daopublic interface MyDao {    @Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")    public User[] loadAllUsersBetweenAges(int minAge, int maxAge);    @Query("SELECT * FROM user WHERE first_name LIKE :search " +           "OR last_name LIKE :search")    public List findUserWithName(String search);}
     
  3. 返回列的子集;在数据库查询结果中经常会只需要某些字段,或者在多表联合查询中需要多张表的字段的情况,这些情况下直接返回定义表的实体对象是不合适的,Room允许你自定义POJO来映射结果集:
    public class NameTuple {    @ColumnInfo(name = "first_name")    public String firstName;    @ColumnInfo(name = "last_name")    public String lastName;}
    @Daopublic interface MyDao {    @Query("SELECT first_name, last_name FROM user")    public List loadFullName();}
     
    Room默认是不允许在UI线程中进行数据操作的,如果要用需要在初始化时调用.allowMainThreadQueries()。基于这种设计哲学,Room对响应式框架非常友好。
     
  4. LiveData;LiveData是Android官方提供的响应式框架,与Room的配合极其简单(Android官方架构工具直接的配合使用都很简洁);在gradle中配置好LiveData相关依赖后,只需要把对应操作的方法返回值用LiveData<>包裹就行了:
    @Daopublic interface MyDao {    @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")    public LiveData> loadUsersFromRegionsSync(List regions);}
     
  5. RxJava;Room为不同的操作提供不同的可观察者对象:
    a. 对于@Query,Room提供Publisher、Flowable和Observable;
    b. 对于@Insert、@Update、 @Delete,Room提供Completable、Single和Maybe;
    使用方式也简单:
    首先在app/build.gradle中配置依赖
    dependencies {    implementation 'androidx.room:room-rxjava2:2.1.0-alpha02'}
    然后和LiveData一样用泛型包裹返回值:
    @Daopublic interface MyDao {    @Query("SELECT * from user where id = :id LIMIT 1")    public Flowable loadUserById(int id);    // Emits the number of users added to the database.    @Insert    public Maybe insertLargeNumberOfUsers(List users);    // Makes sure that the operation finishes successfully.    @Insert    public Completable insertLargeNumberOfUsers(User... users);    /* Emits the number of users removed from the database. Always emits at       least one user. */    @Delete    public Single deleteUsers(List users);}
     
  6. 直接返回Cursor;
    @Daopublic interface MyDao {    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")    public Cursor loadRawUsersOlderThan(int minAge);}

依赖配置

Room属于官方依赖,提供了AndroidX版本和非AndroidX版本,配置都很简单:

  1. 非AndroidX:
    dependencies {    def room_version = "1.1.1"    implementation "android.arch.persistence.room:runtime:$room_version"    annotationProcessor "android.arch.persistence.room:compiler:$room_version" // use kapt for Kotlin    // 可选- RxJava支持    implementation "android.arch.persistence.room:rxjava2:$room_version"}
  2. AndroidX:
    dependencies {    def room_version = "2.1.0-alpha03"    implementation "androidx.room:room-runtime:$room_version"    annotationProcessor "androidx.room:room-compiler:$room_version" // use kapt for Kotlin    // 可选- RxJava支持    implementation "androidx.room:room-rxjava2:$room_version"}

如果要使用LiveData请参考Lifecycle的配置文档配置LiveData相关依赖。

更多相关文章

  1. Android应用程序组件Content Provider的共享数据更新通知机制分
  2. xUtils3.3.x注解使用实例
  3. android 数据库 备份还原
  4. Android ListView SimpleAdapter ArrayList 数据更新问题 zhuan
  5. Android SQLiteOpenHelper(手机数据库)
  6. Android音频口数据通信开发;通过静态分析工具了解IPA实现 -- iOS/
  7. WebView之js调用Android类的方法传递数据 - 依凡王子
  8. Android 实现json网络数据通过BaseAdapter加载到ListView中

随机推荐

  1. android转IOS开发学习计划
  2. android关闭应用
  3. Android 自定义实现TextView单行超出部分
  4. Mac android studio真机调试步骤
  5. AndroidManifest.xml文件剖析 (二)
  6. Android(安卓)Design Support Library -
  7. 浅谈Android常用控件
  8. java android客户端SSL通信 遇到的几个报
  9. Android X库 BiometricPrompt 中 Crypto
  10. Android 混淆代码问题总结