Android架构组件Room指南


当前第2页 返回上一页

LiveData<T>:
LiveData是架构组件库中提供的另一个组件,可以很好满足数据变化驱动UI刷新的需求。Room会实现更新LiveData的代码。

@Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)") 
public LiveData<List<User>> loadUsersFromRegionsSync(List<String> regions);
Flowablbe<T> Maybe<T> Single<T>:
Room 支持返回RxJava2 的Flowablbe, Maybe和Single对象,对于使用RxJava的项目可以很好的衔接, 但需要在gradle添加该依赖:android.arch.persistence.room:rxjava2。
@Query("SELECT * from user where id = :id LIMIT 1")
public Flowable<User> loadUserById(int id);

Cursor:

返回Cursor是为了支持现有项目中使用Cursor的场景,官方不建议直接返回Cursor.

Caution: It's highly discouraged to work with the Cursor API because it doesn't guarantee whether the rows exist or what values the rows contain. Use this functionality only if you already have code that expects a cursor and that you can't refactor easily.

2.4 联表查询

Room支持联表查询,接口定义上与其他查询差别不大, 主要还是sql语句的差别。

@Dao
public interface MyDao {
 @Query("SELECT * FROM book "
  + "INNER JOIN loan ON loan.book_id = book.id "
  + "INNER JOIN user ON user.id = loan.user_id "
  + "WHERE user.name LIKE :userName")
 public List<Book> findBooksBorrowedByNameSync(String userName);
}

3. 创建数据库

Room中DataBase类似SQLite API中SQLiteOpenHelper,是提供DB操作的切入点,但是除了持有DB外, 它还负责持有相关数据表(Entity)的数据访问对象(DAO), 所以Room中定义Database需要满足三个条件:

  • 继承RoomDataBase,并且是一个抽象类
  • 用@Database 注解,并定义相关的entity对象, 当然还有必不可少的数据库版本信息
  • 定义返回DAO对象的抽象方法
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
 public abstract UserDao userDao();
}

创建好以上Room的三大组件后, 在代码中就可以通过以下代码创建Database实例。

AppDatabase db = Room.databaseBuilder(getApplicationContext(),
 AppDatabase.class, "database-name").build();

三、数据库迁移

3.1 Room数据库升级

在传统的SQLite API中,我们如果要升级数据库, 通常在SQLiteOpenHelper.onUpgrade方法执行数据库升级的sql语句,这些sql语句的通常根据数据库版本以文件的方式或者用数组来管理。有人说这种方式升级数据库就像在拆炸弹,相比之下在Room中升级数据库简单的就像是按一个开关而已。

Room提供了Migration类来实现数据库的升级:

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");
 }
};

在创建Migration类时需要指定startVersion和endVersion, 代码中MIGRATION_1_2和MIGRATION_2_3的startVersion和endVersion是递增的, Migration其实是支持从版本1直接升到版本3,只要其migrate()方法里执行的语句正常即可。那么Room是怎么实现数据库升级的呢?其实本质上还是调用SQLiteOpenHelper.onUpgrade,Room中自己实现了一个SQLiteOpenHelper, 在onUpgrade()方法被调用时触发Migration,当第一次访问数据库时,Room做了以下几件事:

  • 创建Room Database实例
  • SQLiteOpenHelper.onUpgrade被调用,并且触发Migration
  • 打开数据库

这样一看, Room中处理数据库升级确实很像是加一个开关。

3.2 原有SQLite数据库迁移至Room

因为Room使用的也是SQLite, 所以可以很好的支持原有Sqlite数据库迁移到Room。

假设原有一个版本号为1的数据库有一张表User, 现在要迁移到Room, 我们需要定义好Entity, DAO, Database, 然后创建Database时添加一个空实现的Migraton即可。需要注意的是,即使对数据库没有任何升级操作,也需要升级版本, 否则会抛异常IllegalStateException.

@Database(entities = {User.class}, version = 2)
public abstract class UsersDatabase extends RoomDatabase {
…
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
 @Override
 public void migrate(SupportSQLiteDatabase database) {
 // Since we didn't alter the table, there's nothing else to do here.
 }
};
…
database = Room.databaseBuilder(context.getApplicationContext(),
 UsersDatabase.class, "Sample.db")
 .addMigrations(MIGRATION_1_2)
 .build();

四、复杂数据的处理

在某些场景下我们的应用可能需要存储复杂的数据类型,比如Date,但是Room的Entity仅支持基本数据类型和其装箱类之间的转换,不支持其它的对象引用。所以Room提供了TypeConverter给使用者自己实现对应的转换。

一个Date类型的转换如下:

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();
 }
}

定义好转换方法后,指定到对应的Database上即可, 这样就可以在对应的POJO(User)中使用Date类了。

@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;
}

五、总结

在SQLite API方式实现数据持久化的项目中,相信都有一个任务繁重的SQLiteOpenHelper实现, 一堆维护表的字段的Constant类, 一堆代码类似的数据库访问类(DAO),访问数据库时需要做Cursor的遍历,构建并返回对应的POJO类...相比之下,Room作为在SQLite之上封装的ORM库确实有诸多优势,比较直观的体验是:

  • 比SQLite API更简单的使用方式
  • 省略了许多重复代码
  • 能在编译时校验sql语句的正确性
  • 数据库相关的代码分为Entity, DAO, Database三个部分,结构清晰
  • 简单安全的数据库升级方案

总结

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


标签:SQLite

返回前面的内容

相关阅读 >>

android中操作Sqlite数据库快速入门教程

c# Sqlite数据库入门使用说明

android编程之数据库的创建方法详解

实例讲解Sqlite迁移到mysql脚本的方法_

python 操作Sqlite数据库详情

Sqlite3 api 编程手册

asp.net下Sqlite(轻量级最佳数据库) 原理分析和开发应用

android将图片转换存到数据库再从数据库读取转换成图片实现代码

迅雷高速通道怎么破解使用?迅雷高速通道无限使用破解教程详解

android中数据库常见操作实例分析

更多相关阅读请进入《Sqlite》频道 >>


数据库系统概念 第6版
书籍

数据库系统概念 第6版

机械工业出版社

本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...