Room其实就是一个orm,抽象了SQLite的使用,原生支持LiveData和Rxjava嵌套使用。

Room有3个主要组件

  • Database :数据库
  • Entity : 代表数据库一个表结构
  • Dao : 包含访问数据库的方法

简单使用

添加依赖

dependencies {// Roomimplementation "android.arch.persistence.room:runtime:1.0.0"annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
}

定义数据表实体类

当一个类用@Entity注解并且被@Database注解中的entities属性所引用,Room就会在数据库中为那个entity创建一张表。

Room默认把类名作为数据库的表名。如果你想用其它的名称,使用@Entity注解的tableName属性。

默认Room会为entity中定义的每一个field都创建一个column。和tableName属性类似,Room默认把field名称作为数据库表的column名。如果你想让column有不一样的名称,为field添加@ColumnInfo属性。如果一个entity中有你不想持久化的field,那么你可以使用@Ignore来注释它们。

要持久化一个field,Room必须有获取它的渠道。你可以把field写成public,也可以为它提供一个setter和getter。如果你使用setter和getter的方式,记住它们要基于Room的Java Bean规范。

每个entity必须至少定义一个field作为主键(primary key)。即使只有一个field,你也必须用@PrimaryKey注释这个field。如果你想让Room为entity设置自增ID,你可以设置@PrimaryKey的autoGenerate属性。如果你的entity有一个组合主键,你可以使用@Entity注解的primaryKeys属性。

@Entity(tableName = "tb_class")
public class ClassEntity {@PrimaryKeyprivate long id;
}
//指示数据表实体类
@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
}

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);@Insertvoid insert(StudentEntity... entities);@Deletevoid delete(StudentEntity entity);@Updatevoid update(StudentEntity entity);
}

@insert, @Update都可以执行事务操作,定义在OnConflictStrategy注解类中

public @interface Insert {//定义处理冲突的操作@OnConflictStrategyint 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() {//第一次创建数据库时调用,但是在创建所有表之后调用的@Overridepublic void onCreate(@NonNull SupportSQLiteDatabase db) {super.onCreate(db);}//当数据库被打开时调用@Overridepublic 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) {@Overridepublic 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) {@Overridepublic 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 {@PrimaryKeypublic int id;public String firstName;@Embeddedpublic Address address;
}

这样user表中的字段就包含了idfirstNamestreetstatecity, 和 post_code

注意:嵌入式字段还可以包含其他嵌入式字段

如果一个实体具有相同类型的多个内嵌字段,则可以通过设置前缀属性(prefix)使每个列保持惟一。然后将所提供的值添加到嵌入对象中每个列名的开头。

@Embedded(prefix = "foo_")Coordinates coordinates;

LiveData一起使用

添加依赖

// ReactiveStreams support for LiveDataimplementation "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 Roomimplementation "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 {@TypeConverterpublic static Date fromTimestamp(Long value) {return value == null ? null : new Date(value);}@TypeConverterpublic 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文件(表示数据库的模式历史记录)存储在您的版本控制系统中,因为它允许为测试目的创建您的数据库的旧版本

Android Room的使用相关推荐

  1. Unity5.6+ 导出Android 应用程序apk的环境配置及导出过程

    首先下载并安装安卓SDK和java的JDK 安卓sdk下载: http://www.android-studio.org/ 也可以在这下载: 链接:http://pan.baidu.com/s/1bp ...

  2. Android 的NDK的Makefile编写

    Android.mk 是google根据Linux GNU Makefile精简编译脚本.具体来说:这就是GNU Makefile的一小部分. 举一个简单例子: LOCAL_PATH := $(cal ...

  3. Android Animation (安卓动画)概念简介

    Android Animation Android 四种动画分别为逐帧动画和补间动画.属性动画.过渡动画: Frame Animation (逐帧动画) 实现方式:xml 和 Java代码 图片跳转的 ...

  4. 基于Android和SpringBoot的购物App

    (Shopping)购物应用商城 本软件使用Android和SpringBoot.JavaWeb技术实现:并结合百度LBS平台的SDK.支付宝App支付客户端SDK.MobTech的ShareSDK: ...

  5. Android数据持久化:SharePreference

    SharePreference:作为Android数据持久化的一种,具有一定的便捷性,适合存储一些体积小的数据. 存储数据方式:键值对的方式,类似于Map: 利用SharePreference.Edi ...

  6. Android数据持久化:文件存储

    数据持久化: 数据可分为瞬时数据和关键数据.保存在内存之中的数据是瞬时数据,而对于一些关键性数据,后期需要持续使用的,应当保存在存储设备中: 持久化保存方式: 文件存储.SharePreference ...

  7. Android Studio中RecycerView依赖库加载问题

    依赖包导入思考: 参考资料:recycleview导包问题 打开修改本项目中的build.gradle; 切勿着急添加包,应当提前查看其中的版本号(因为加载的v7包要和其版本保持一致性): 例如: 因 ...

  8. Android布局优化之include、merge、ViewStub

    include:引入重复使用的相同布局 merge:减少include布局的层级,将子元素直接添加到merge标签的parent中 ViewStub:其实就是一个宽高都为0的一个View,它默认是不可 ...

  9. Android动画之帧动画和补间动画

    Android系统提供三种动画:帧动画.补间动画和属性动画.这里先分析总结帧动画和补间动画. FrameAnimation 帧动画,通俗来说就是按照图片动作顺序依次播放来形成动画,创建帧动画可以用 x ...

  10. Android系统的启动过程

    Android系统的启动过程可以简单地总结为以下几个流程: 加载BootLoader -> 初始化内核 -> 启动init进程 -> init进程fork出Zygote(孵化器)进程 ...

最新文章

  1. Maven环境配置及IntelliJ IDEA中的Maven部署(亲自测试)
  2. SSH与EJB 比较
  3. Bailian2688 求字母的个数【输入流】
  4. 熬,是人生最深的滋味
  5. OrzFAng系列–树 解题报告
  6. 模拟电子技术基础笔记(1)
  7. word多级标题的使用
  8. 简账(开源记账软件)-数据库设计
  9. jsmind 线条_使用jsMind显示思维导图
  10. 石英晶体振荡器的检定方法
  11. c语言将时速转换成配速,配速与时速换算(跑步配速和时速换算)
  12. 如何使用Redis Streams
  13. 山西大学计算机与信息技术学院张超,张超 - 山西大学 - 计算机与信息技术学院...
  14. 大赞!像 Github 一样管理你的 Word 文档
  15. 浏览器书签同步插件EverSync
  16. PX环境搭建编译px4_fmu-v2_default相关问题的解决方法
  17. 从零开始学习HarmonyOS应用开发——1
  18. 使用 you-get 下载视频
  19. UOS系统升级到1050后无法正常使用输入法功能问题解决方法
  20. 2020汽车修理工(中级)实操考试视频及汽车修理工(中级)考试试题

热门文章

  1. GuzzleHttp使用
  2. 在你的时区里,一切准时-很美的英文诗
  3. 浏览器提示代理服务器没有响应
  4. jpress转换html5,JPress技术精讲:JPress如何做到安装后重新加载的?
  5. java log4j详解_log4j详解
  6. git报错Push to origin/master was rejected的解决办法
  7. json vs jsonb,及常用
  8. 《亚马逊云科技-游戏孵化营》第一次公开课学习心得
  9. Iaas、Paas、Saas都是什么意思?
  10. 吾生也有涯,而知也无涯,以有涯随无涯,殆己