Android官方ORM Room介绍
Android官方ORM Room介绍
基本使用
- 通过实体类和注解定义表数据:
Entitypublic class User { @PrimaryKey public int uid; @ColumnInfo(name = "first_name") public String firstName; @ColumnInfo(name = "last_name") public String lastName;}
- 创建具体操作的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);}
- 定义继承自RoomDatabase的数据库类,在这个类中定义创建Dao类的接口,是抽象类,Room将在编译时生成具体的实现类:
@Database(entities = {User.class}, version = 1)public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao();}
- 在代码中使用:
//创建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();}
-
主键
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; }
-
忽略实体字段;一般情况下,实体中所有字段都会在表中创建一个列,当要某些字段不需要创建列时,可以通过添加注解@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;}
-
查询优化;
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;}
-
嵌套对象;有时候,一个表中的几个列在应用逻辑上更适合组合成一个实体,但是为这几个字段单独建表又感觉没必要,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对象,反之亦然。
-
视图;通过注解@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();}
- 多种方法模板;对于不同的应用场景,Room提供了不同类型的方法:
每个方法都可以设置返回值,如果只操作一个数据(只有一个传入参数),则返回一个long型的数据,也就是被操作数据的rowID,如果操作一组数据则返回这一组数据的rowID,返回值应该long[] 或者 List< Long >。@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);}
- 查询参数绑定;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);} - 返回列的子集;在数据库查询结果中经常会只需要某些字段,或者在多表联合查询中需要多张表的字段的情况,这些情况下直接返回定义表的实体对象是不合适的,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对响应式框架非常友好。
- 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);} - RxJava;Room为不同的操作提供不同的可观察者对象:
a. 对于@Query,Room提供Publisher、Flowable和Observable;
b. 对于@Insert、@Update、 @Delete,Room提供Completable、Single和Maybe;
使用方式也简单:
首先在app/build.gradle中配置依赖
然后和LiveData一样用泛型包裹返回值:dependencies { implementation 'androidx.room:room-rxjava2:2.1.0-alpha02'}
@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);} - 直接返回Cursor;
@Daopublic interface MyDao { @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5") public Cursor loadRawUsersOlderThan(int minAge);}
依赖配置
Room属于官方依赖,提供了AndroidX版本和非AndroidX版本,配置都很简单:
- 非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"}
- 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相关依赖。
更多相关文章
- Android应用程序组件Content Provider的共享数据更新通知机制分
- xUtils3.3.x注解使用实例
- android 数据库 备份还原
- Android ListView SimpleAdapter ArrayList 数据更新问题 zhuan
- Android SQLiteOpenHelper(手机数据库)
- Android音频口数据通信开发;通过静态分析工具了解IPA实现 -- iOS/
- WebView之js调用Android类的方法传递数据 - 依凡王子
- Android 实现json网络数据通过BaseAdapter加载到ListView中