赞
踩
Room 是 Android 提供的一个持久性库,用于在 SQLite 数据库之上提供更高级的抽象层。它旨在简化数据库操作并提供更强大的功能,同时结合了 SQLite 的强大特性。
Room 提供了许多优点:
Room 由三个主要组件组成:
1.Entity(实体): 表示数据库中的表结构。每个 Entity 对应于数据库中的一张表,并且通过注解来定义。Entity 包含表中的字段以及与数据库中的行对应的数据。
2.DAO(Data Access Object,数据访问对象): 提供数据库操作的方法。通过在 DAO 中定义 SQL 查询或操作方法,并使用注解来标识这些方法,Room 可以在编译时为这些方法生成相应的实现。
3. Database(数据库): 是数据库的抽象层,它包含数据库的持有者并提供连接的主要访问点。Database 类应该是抽象类并继承自 RoomDatabase。它通常是一个单例,用于获取 DAO 实例并执行数据库操作。
官方文档:https://developer.android.com/training/data-storage/room?hl=zh-cn#groovy
在app的build.gradle中添加依赖:
def room_version = "2.4.2" implementation "androidx.room:room-runtime:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version" // optional - RxJava2 support for Room implementation "androidx.room:room-rxjava2:$room_version"
android {
...
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments += [
"room.schemaLocation":"$projectDir/schemas".toString(),
"room.incremental":"true",
"room.expandProjection":"true"]
}
}
}
}
1. "room.schemaLocation":"$projectDir/schemas".toString(): 的作用是将配置并启把据库架构导出json文件到指定目录。
2."room.incremental":"true":启用 Gradle 增量注解处理器。
3."room.expandProjection":"true": 配置 Room 以重写查询,使其顶部星形投影在展开后仅包含 DAO 方法返回类型中定义的列。
如果配置了schemaLocation,编译后,会在对应路径生成schemas文件夹,json包含了各个版本的概要,表结构等信息:
@Entity(tableName = "user",primaryKeys = {"deviceId", "themeId"}) public class User { @NonNull public String deviceId;//主键--设备id @ColumnInfo public long themeId;//主键 @ColumnInfo public String options; @ColumnInfo public long createdAt; @ColumnInfo public long updatedAt; @ColumnInfo public String userName; }
创建表一般会用到下面几个注解:
@Entity(tableName=“表名称”): @Entity表示定义数据库中的一个表,通常Room会使用类名作为数据库的表名,如果你希望自定义表名可以配置@Entity(tableName = “user”),注意:SQLite中,表名是不区分大小写的。
@PrimaryKey(autoGenerate=true): 定义主键 autoGenerate 用于设置主键自增,默认为false。
@ColumnInfo(name = “别名”): Room默认用变量名称作为数据库表的字段名称,如果你希望字段名称和变量名称不一样,则需要给变量添加@ColumnInfo注解。
@Ignore: 忽略该字段,加上该注解不会将该字段映射到数据库中去。
索引和唯一性:根据操作数据的方式可能需要通过索引来提高查询数据库的速度,通过@Entity添加indices属性,有些字段设置唯一性,可以通过@Index注解下设置unique为true。
@Entity(indices = [Index(value =["deviceId"], unique = true)])
@Dao public interface UserDao { @Insert void insertUsers(User... users); @Delete void deleteUsers(User... users); @Update void updateUsers(User... users); @Query("select * from user") List<User> getAllUsers(); @Query("select * from user where deviceId in (:deviceIds)") List<User> getAllUsersByDeviceId(String[] deviceIds); @Query("select * from user where deviceId = :deviceId limit 1") User getUserByDeviceId(String deviceId); @Query("select * from user where deviceId = :deviceId and themeId = :themeId") User getUser(String deviceId,long themeId); }
Room 使用注解处理器映射了数据库的增删改查,即 @Insert、@Delete、@Update、@Query 代表我们常用的插入、删除、更新、查询数据库操作。
@Query非常的强大,你可以编写任意sql语句并得到你想要的结果。
是一个继承于RoomDatabase 的抽象类。
在注解中包括与数据库相关联的实体列表。
包含一个没有参数的抽象方法并且返回一个带有注解的@Dao。
在运行时,我们可以通过调用 Room.databaseBuilder()或 Room.inMemoryDatabaseBuilder()
来获取 Database 的实例。
@Database(entities = {User.class, VoteStatistics.class, CountOptions.class, VoteTheme.class},version = 3,autoMigrations = {@AutoMigration(from = 1, to = 2),@AutoMigration(from = 2, to = 3)}) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao getUserDao(); public static final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(@NonNull SupportSQLiteDatabase database) { //执行升级相关操作 database.execSQL("DROP TABLE IF EXISTS user"); } }; public static final Migration MIGRATION_2_3 = new Migration(2, 3) { @Override public void migrate(@NonNull SupportSQLiteDatabase database) { //执行升级相关操作 database.execSQL("ALTER TABLE vote_theme ADD testId INTEGER Default 0 not null"); } }; }
@Database 表示继承自RoomDatabase的抽象类,entities指定Entities表的实现类,version指定了DB版本。
必须提供获取DAO接口的抽象方法,比如上面定义的getUserDao(),RoomDatabase将通过这个方法实例化DAO接口。
public class DatabaseManager {
private AppDatabase db;
public DatabaseManager() {
//context可用applicationcontext代替
db = Room.databaseBuilder(MyApplication.getInstance(), AppDatabase.class, "voter.db")
.build();
}
public List<User> getAllUsers() {
UserDao userDao = db.getUserDao();
return userDao.getAllUsers();
}
public void addUser(User user) {
UserDao userDao = db.getUserDao();
User result = userDao.getUserByDeviceId(user.deviceId);
if (result == null) {
userDao.insertUsers(user);
} else {
userDao.updateUsers(user);
}
}
public void deleteUser(User user) {
UserDao userDao = db.getUserDao();
userDao.deleteUsers(user);
}
}
RoomDatabase实例的内存开销较大,建议使用单例模式管理。
点击Build编译项目,Room会自动生成对应的_Impl实现类,此处将生成AppRoomDataBase_Impl.java文件。
db = Room.databaseBuilder(MyApplication.getInstance(), AppDatabase.class, "voter.db") .addCallback(new RoomDatabase.Callback() { @Override public void onCreate(@NonNull SupportSQLiteDatabase db) { super.onCreate(db); } @Override public void onOpen(@NonNull SupportSQLiteDatabase db) { super.onOpen(db); } @Override public void onDestructiveMigration(@NonNull SupportSQLiteDatabase db) { super.onDestructiveMigration(db); } }) .build();
比如:可通过该方式 在open回调中,在数据库打开时设置同步模式,该方法会保证数据库操作数据同步写入本地磁盘,防止部分机型在断电等情况下数据未及时写入本地数据库导致数据丢失。
db = Room.databaseBuilder(MyApplication.getInstance(), AppDatabase.class, "voter.db") // .addMigrations(MIGRATION_1_2) .addCallback(new RoomDatabase.Callback() { @Override public void onCreate(@NonNull SupportSQLiteDatabase db) { super.onCreate(db); } @Override public void onOpen(@NonNull SupportSQLiteDatabase db) { super.onOpen(db); // 在数据库打开时设置同步模式 db.execSQL("PRAGMA synchronous = FULL;"); // 设置同步模式为OFF } @Override public void onDestructiveMigration(@NonNull SupportSQLiteDatabase db) { super.onDestructiveMigration(db); } }) .build();
db = Room.databaseBuilder(MyApplication.getInstance(), AppDatabase.class, "voter.db") .addMigrations(MIGRATION_1_2) .build();
如果您的应用在多个进程中运行,请在数据库构建器调用中包enableMultiInstanceInvalidation()。这样,如果您在每个进程中都有一个 AppDatabase 实例,就可以在一个进程中使共享数据库文件失效,并且这种失效会自动传播到其他进程中的 AppDatabase 实例,默认不开启。
不提供数据库迁移,又不想引发 crash 。但是注意数据会丢失删除数据库重建
如果您仅在从较高数据库版本迁移到较低数据库版本时才希望 Room 回退到破坏性重新创建,请用该方法
设置数据库的工厂类,如果没有设置。则默认使用内置的 FrameworkSQLiteOpenHelperFactory
启用一个数据库打开后空闲没有使用资源的自动关闭策略
设置数据库的日志模式,如果使用内存数据库构建请忽略此值
每当数据库执行查询操作时候回调,不建议在生产环境使用
设置查询的线程池一般不需要设置,会使用默认的 ArchTaskExecutor 内置线程池
设置事务线程池一般不需要设置,会使用查询方法的默认线程池,详可见源码 RoomDatabase.java#build()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。