- 前言
- Room 基本使用
- Book - @Entity
- BookDao - @Dao
- AppDatabase - @Database
- RoomActivity - 调用
- Room 相关API
- 使用@Entity创建表(数据实体)
- 使用@Dao,创建操作数据库的接口(数据访问对象)
- 使用@Database,创建数据库
- 存储位置
- 升级
- 扩展
- 参考地址
Jetpack 是一个丰富的组件库,它的组件库按类别分为 4 类,分别是架构(Architecture)、界面(UI)、 行为(behavior)和基础(foundation)。
每个组件都可以单独使用,也可以配合在一起使-用。每个组件都给用户提供了一个标准, 能够帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者能够集中精力编写重要的业务代码。
Room 基本使用这里的使用是Room + RxJava的方式,需要引用依赖:
implementation 'androidx.room:room-runtime:2.3.0' implementation 'androidx.room:room-rxjava2:2.3.0' annotationProcessor "androidx.room:room-compiler:2.3.0"
同时,需要添加:
defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] } }
方便我们查看数据库架构信息。
如果项目中已经存在 javaCompileOptions 定义arguments 内容,可以写一起:
javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName(),"room.schemaLocation": "$projectDir/schemas".toString()] } }
Book 是我们需要的JavaBean
BookDao 是对Book操作的封装(增删减查)
AppDatabase 是数据库的创建和更新
RoomActivity 是调用的地方
@Entity(tableName = "book_table") public class Book { public Book() { } @Ignore public Book(Long uid) { this.uid = uid; } @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "uid") private Long uid; private String name; private String address; public Long getUid() { return uid; } public void setUid(Long uid) { this.uid = uid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }BookDao - @Dao
@Dao public interface BookDao { @Insert(onConflict = OnConflictStrategy.REPLACe) SingleAppDatabase - @Database> insert(Book... books); @Query("SELECT * from book_table") Single
> queryAll(); int QUERY_BOOK_LENGTH = 2; @Query("SELECt * FROM book_table LIMIT :start," + QUERY_BOOK_LENGTH) Single
> query2(int start); @Query("select * from book_table where name =:name") Single
> queryName(String name); @Update Single
update(Book... books); @Delete Single delete(Book... books); @Query("DELETE FROM book_table") Single deleteAll(); @Query("delete from book_table where name =:name") Single deleteName(String name); }
@Database(entities = {Book.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract BookDao bookDao(); private static volatile AppDatabase database; public static AppDatabase getInstance(Context context) { if (database == null) { synchronized (AppDatabase.class) { if (database == null) { database = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "book.db").build(); } } } return database; } }RoomActivity - 调用
@Route(path = "/main/RoomActivity") public class RoomActivity extends BaseActivity { int query_start = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_room); rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_insert)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Book book = new Book(); book.setName("哈利波特"); Disposable disposable = AppDatabase.getInstance(this).bookDao() .insert(book) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new ConsumerRoom 相关API 使用@Entity创建表(数据实体)>() { @Override public void accept(List
longs) throws Exception { AppLogUtils.i(TAG, "insert longs==" + new Gson().toJson(longs)); } }); })); rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_query)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Disposable disposable = AppDatabase.getInstance(this).bookDao() .queryAll() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer >() { @Override public void accept(List
books) throws Exception { AppLogUtils.i(TAG, "queryAll books==" + new Gson().toJson(books)); } }); })); rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_query_2)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Disposable disposable = AppDatabase.getInstance(this).bookDao() .query2(query_start) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer >() { @Override public void accept(List
books) throws Exception { query_start = query_start + QUERY_BOOK_LENGTH; AppLogUtils.i(TAG, "queryAll books==" + new Gson().toJson(books)); } }); })); rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_query_name)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Disposable disposable = AppDatabase.getInstance(this).bookDao() .queryName("哈利波特") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer >() { @Override public void accept(List
books) throws Exception { AppLogUtils.i(TAG, "queryName books==" + new Gson().toJson(books)); } }); })); rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_update)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Book book = new Book(); book.setName("哈利波特2"); book.setUid(12L); book.setAddress("美丽国是NC"); Disposable disposable = AppDatabase.getInstance(this).bookDao() .update(book) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer () { @Override public void accept(Integer integer) throws Exception { AppLogUtils.i(TAG, "update longs==" + new Gson().toJson(integer)); } }); })); rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_delete)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Book book = new Book(); book.setUid(1L); Book[] books = new Book[]{new Book(102L),new Book(103L)}; Disposable disposable = AppDatabase.getInstance(this).bookDao() .delete(books) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer () { @Override public void accept(Integer integer) throws Exception { AppLogUtils.i(TAG, "delete longs==" + new Gson().toJson(integer)); } }); })); rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_delete_all)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Disposable disposable = AppDatabase.getInstance(this).bookDao() .deleteAll() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer () { @Override public void accept(Integer integer) throws Exception { AppLogUtils.i(TAG, "delete longs==" + new Gson().toJson(integer)); } }); })); rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_delete_name)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Disposable disposable = AppDatabase.getInstance(this).bookDao() .deleteName("哈利波特") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer () { @Override public void accept(Integer integer) throws Exception { AppLogUtils.i(TAG, "deleteName longs==" + new Gson().toJson(integer)); } }); })); } }
- 设置表名
@Entity(tableName = "table_book")
- 主键
@NonNull //主键不能为null @PrimaryKey(autoGenerate = true) //主键是否自动增长,默认为false private int id;
设置增长后,默认uid会从1开始向上加,如果有最大值是99(人为插入),那么下一个默认值从100开始
- 复合键
如果你需要通过多个列的组合来唯一标识实体的实例,你可以通过在 @Entity 的 primaryKeys 属性中列出这些列来定义复合主键:
@Entity(tableName = "users",primaryKeys = {"mName","mAge"}) public class User { public String mName; public int mAge; }
- 字段重命名
@ColumnInfo(name = "firstName") private int first;
可以通过设置name =xxx 的方式重新命名字段
- 嵌套类
这个注解可以将普通JavaBan中的字段也引入到对应的表中,查询结果会自动为对应的bean。使用此注解将实现嵌套类的直接存储。
@Entity(tableName = "book_table") public class Book { public Book() { } @Embedded private Chapter chapter; public Chapter getChapter() { return chapter; } public void setChapter(Chapter chapter) { this.chapter = chapter; } ... }
Chapter 类不需要额外处理,只需要添加Set/get方法
- 忽略构造函数 和 忽略字段
对于构造函数来讲,每个表对应的JavaBean只能有一个主构造方法,若还有其它的构造方法则必须使用@Ignore注解进行标识
@Entity(tableName = "book_table") public class Book { public Book() { } @Ignore public Book(Long uid) { this.uid = uid; }
对于字段来讲,如果你想哪个字段不映射到数据库中存储起来,即可设置
@Ignore private String age;使用@Dao,创建操作数据库的接口(数据访问对象)
DAO 负责定义访问数据库的方法。使用 Room,我们不需要所有与 Cursor 相关的代码,只需使用 UserDao 类中的注释定义我们的查询即可。每个 DAO 都包含提供对应用程序数据库的抽象访问的方法。在编译时,Room 会自动生成您定义的 DAO 的实现。
你可以将 DAO 定义为接口或抽象类。对于基本用例,通常应该使用接口。无论哪种情况,都必须使用 @Dao 注释你的 DAO。DAO 没有属性,但它们确实定义了一种或多种方法来与应用程序数据库中的数据进行交互。
使用@Database,创建数据库 存储位置数据库保存路径为应用的内部存储空间:/data/data/com.yoshin.tsp/databases/book.db
- 数据库升级 填字段:
@Database(entities = {Book.class}, version = 2) public abstract class AppDatabase extends RoomDatabase { public abstract BookDao bookDao(); private static volatile AppDatabase database; public static AppDatabase getInstance(Context context) { if (database == null) { synchronized (AppDatabase.class) { if (database == null) { database = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "book.db") .addMigrations(MIGRATION_1_2) .build(); } } } return database; } static final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(@NonNull SupportSQLiteDatabase database) { database.execSQL("ALTER TABLE book_table ADD COLUMN issueTime TEXT Default "" "); database.execSQL("ALTER TABLE book_table ADD COLUMN version INTEGER NOT NULL DEFAULT 0"); } };
向表中添加字段 issueTime 、version ,同时赋予默认值
另外,向表中添加实体类的写法不会写,记录一下~,请大佬给指点下
- 数据库升级 填新表:
Entity:
@Entity(tableName = "stationery_table") public class Stationery { @NonNull @PrimaryKey(autoGenerate = true) private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
Dao:
@Dao public interface StationeryDao { @Insert(onConflict = OnConflictStrategy.REPLACE) Single> insert(Stationery... stationeries); @Query("SELECT * from stationery_table") Single
> queryAll(); }
Database:
@Database(entities = {Book.class, Stationery.class}, version = 3) public abstract class AppDatabase extends RoomDatabase { public abstract BookDao bookDao(); public abstract StationeryDao stationeryDao(); private static volatile AppDatabase database; public static AppDatabase getInstance(Context context) { if (database == null) { synchronized (AppDatabase.class) { if (database == null) { database = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "book.db") // .addMigrations(MIGRATION_1_2) .addMigrations(MIGRATION_1_2, MIGRATION_2_3) .build(); } } } return database; } static final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(@NonNull SupportSQLiteDatabase database) { database.execSQL("ALTER TABLE book_table ADD COLUMN issueTime TEXT Default "" "); database.execSQL("ALTER TABLE book_table ADD COLUMN version INTEGER NOT NULL DEFAULT 0"); } }; static final Migration MIGRATION_2_3 = new Migration(2, 3) { @Override public void migrate(SupportSQLiteDatabase database) { database.execSQL("CREATE TABLE stationery_table " + "(id INTEGER PRIMARY KEY NOT NULL," + " name TEXT" + ")" ); } };
调用:
rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_insert_c)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Stationery stationery = new Stationery(); stationery.setName("文具盒"); Disposable disposable = AppDatabase.getInstance(this).stationeryDao() .insert(stationery) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer扩展>() { @Override public void accept(List
longs) throws Exception { AppLogUtils.i(TAG, "insert longs==" + new Gson().toJson(longs)); } }); })); rxViewGcUtil.add(RxView.clicks(findViewById(R.id.btn_query_c)) .throttleFirst(1, TimeUnit.SECONDS) .subscribe(unit -> { Disposable disposable = AppDatabase.getInstance(this).stationeryDao() .queryAll() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer >() { @Override public void accept(List
stationeries) throws Exception { AppLogUtils.i(TAG, "queryAll stationeries==" + new Gson().toJson(stationeries)); } }); }));
还有其他的依赖可以配合 room 使用,先记录
// optional - Guava support for Room, including Optional and ListenableFuture implementation "android.arch.persistence.room:guava:$room_version" // Test helpers testImplementation "android.arch.persistence.room:testing:$room_version"参考地址
转自 Android Jetpack架构全家桶,学完可从零搭建一个Android项目架构:http://px.sxjnk.cn/enjoy/advertorial/article_6
Room数据库学习记录:https://blog.csdn.net/qq_52332769/article/details/122960808
Android 数据存储(四)-Room
:https://blog.csdn.net/g984160547/article/details/122825287
Room官方文档(翻译)0.概览:https://juejin.cn/post/6844903987230015496