Android架构组件Room的使用详解

Room其实就是一个orm,抽象了SQLite的使用,但是它作为Android的亲儿子orm,并且原生支持LiveData和Rxjava嵌套使用,学习一下还是不错的。

Room有3个主要组件

  • 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"
}

定义数据表实体类

班级表

@Entity(tableName = "tb_class")
public class ClassEntity {
  @PrimaryKey
  private 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
}

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_code

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

如果一个实体具有相同类型的多个内嵌字段,则可以通过设置前缀属性(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文件(表示数据库的模式历史记录)存储在您的版本控制系统中,因为它允许为测试目的创建您的数据库的旧版本

总结

以上所述是小编给大家介绍的Android架构组件Room的使用详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

您可能感兴趣的文章:

  • Android架构组件Room指南
(0)

相关推荐

  • Android架构组件Room指南

    一.简介 Room是Google推出的Android架构组件库中的数据持久化组件库, 也可以说是在SQLite上实现的一套ORM解决方案. Room主要包含三个部分: Database : 持有DB和DAO Entity : 定义POJO类,即数据表结构 DAO(Data Access Objects) : 定义访问数据(增删改查)的接口 其关系如下图所示: Room Architecture Diagram 二.基本使用 1. 创建Entity 1.1 一个简单的Entitiy 一个简单Ent

  • Android架构组件Room的使用详解

    Room其实就是一个orm,抽象了SQLite的使用,但是它作为Android的亲儿子orm,并且原生支持LiveData和Rxjava嵌套使用,学习一下还是不错的. Room有3个主要组件 Database :数据库 Entity : 代表数据库一个表结构 Dao : 包含访问数据库的方法 简单使用 添加Google Maven仓库 allprojects { repositories { jcenter() google() } } 添加依赖 dependencies { // Room i

  • Android四大组件之广播BroadcastReceiver详解

    定义 BroadcastReceiver,"广播接收者"的意思,顾名思义,它就是用来接收来自系统和应用中的广播.在Android系统中,广播体现在方方面面,例如当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的功能:当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作:当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度等等.Android中的广播机制设计的非常出色,很多事情原本需要开发者亲自操作的,现

  • Android Jetpack组件ViewModel基本用法详解

    目录 引言 一.概述与作用 二.基本用法 小结 引言 天道好轮回,终于星期五,但是还是忙碌了一天.在项目中,我遇到了一个问题,起因则是无法实时去获取信息来更新UI界面,因为我需要知道我是否获取到了实时信息,我想到的办法有三,利用Handler收发消息在子线程与主线程切换从而更新信息,其二则是利用在页面重绘的时候(一般是页面变动如跳转下个页面和将应用切至后台),其三就是利用Jetpack中最重要的组件之一ViewModel,最后我还是选择了ViewModel,因为感觉更方便. 其实想到的前面两个方

  • Android框架组件Lifecycle的使用详解

    1.前言 Lifecycle是Google推出的一系列的框架组件的其中一个,主要是用来感知Activity和Fragment的生命周期. 本文主要介绍如何使用Lifecycle. 2.一个常见的开发例子 public class TestActivity extends Activity{ @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceSta

  • Android UI组件LinearLayout线性布局详解

    LinearLayout 线性布局,该布局的继承关系: 1. 什么是线性布局 通俗的说感觉起来和线有关,参照线的特点,有么是横向的,要么是竖向的. LinearLayout是线性布局控件,它包含的子控件将以横向或竖向的方式排列(通过android:orientation属性来控制),按照相对位置来排列所有的widgets或者其他的containers,超过边界时,某些控件将缺失或消失 2. 线性布局常用基本属性 - android:id - android:orientation - andro

  • Android Fragment滑动组件ViewPager的实例详解

    Android Fragment滑动组件ViewPager的实例详解 1适配器FragmentPagerAdapter的实现 对于FragmentPagerAdapter的派生类,只需要重写getItem(int)和getCount()就可以了. public class MyFragmentPagerAdapter extends FragmentPagerAdapter { private List<Fragment> list; public MyFragmentPagerAdapter

  • Android开发Jetpack组件WorkManager用例详解

    目录 一.简介 二.导入 三.基本使用 3.1 定义后台任务 3.2 配置任务运行条件 3.2.1 只需执行一次的任务 3.2.2 周期性执行的任务 3.3 将任务传给 WorkManager 四.高级配置 4.1 设置任务延迟执行 4.2 给任务添加标签 4.3 取消任务 4.3.1 根据标签取消任务 4.3.2 根据 request 的 id 取消任务 4.3.3 取消所有任务 4.4 任务重试 4.5 监听任务结果 4.6 传递数据 4.7 链式任务 一.简介 WorkManager 用于

  • Android开发Jetpack组件DataBinding用例详解

    目录 简介 使用方式 1. build.gradle 中添加 kapt,并启用dataBinding 2.修改布局文件,添加 layout 和 data 标签 3.使用 DataBindingUtil 绑定布局 4.布局的 data 标签中添加数据变量,并使用其参数 5.BindingAdapter的使用 简介 DataBinding 是 Jetpack 组件之一,适用于 MVVM 模式开发,也是Google官方推荐使用的组件之一.使用DataBinding可以很容易的达到视图与逻辑分离,直接在

  • Android组件之服务的详解

    目录 一.服务的概念 二.Android的多线程编程 2.1 线程的基本用法 2.2 在子线程中更新UI 更新方式一 更新方式二 2.3 解析异步消息处理机制 2.4 使用AsyncTask 三.服务的基本用法 3.1 首先定义一个服务 3.2 MyService类里重写几个方法 3.3 在注册文件中完成对服务的注册 3.4 启动和停止服务 3.5 活动和服务进行通信 四.服务的生命周期 五.服务的更多技巧 5.1 使用前台服务 5.2 服务中的多线程问题&IntentService 一.服务的

随机推荐