Android Room数据库入门| 青训营笔记

594 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第2天

使用Room

添加依赖

def room_version = "2.4.2"
//implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
//implementation 'io.reactivex.rxjava3:rxjava:3.1.4'
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
​
// optional - RxJava3 support for Room
implementation "androidx.room:room-rxjava3:$room_version"

简单定义和概览

Room是一个关系映射数据库,ORM (Object Relational Mapping)

构成结构

  • Entity

每一个实体对于Room数据库的一个表

每一个实例代表数据库的一行

实例属性代表数据库的列

  • Dao

Dao 是数据访问对象的意思。在Dao层封装数据库增删查改地方法。

  • Database

用于定义数据库的关键信息,包括数据库的实体类、版本号、以及提供Dao层访问的实例

1:创建实体

@Entity//代表为数据库表
public class User {
    @PrimaryKey//定义主键
    public int id;
​
    public String firstName;
    public String lastName;
}

注意:要保留某个字段,Room 必须拥有该字段的访问权限。您可以通过将某个字段设为公开或为其提供 getter 和 setter 方法,确保 Room 能够访问该字段。

表名和列名的设置

默认情况下,Room 将类名称用作数据库表名称。如果您希望表具有不同的名称,请设置 @Entity 注解的 tableName 属性。同样,Room 默认使用字段名称作为数据库中的列名称。如果您希望列具有不同的名称,请将 @ColumnInfo 注解添加到该字段并设置 name 属性。以下示例演示了表和列的自定义名称:

如果您需要 Room 为实体实例分配自动 ID,请将 @PrimaryKeyautoGenerate 属性设为 true

默认情况下,Room 会为实体中定义的每个字段创建一个列。 如果某个实体中有您不想保留的字段,则可以使用 @Ignore 为这些字段添加注解,如以下代码段所示:

@Entity
public class User {
    @PrimaryKey
    public int id;
​
    public String firstName;
    public String lastName;
​
    @Ignore
    Bitmap picture;
}

支持全文搜索(FTS)full text search, 以加快查询速度

以通过将 @Index 注解的 unique 属性设为 true,强制实施此唯一性属性。以下代码示例可防止表格具有包含 firstNamelastName 列的同一组值的两行。

// Use `@Fts3` only if your app has strict disk space requirements or if you
// require compatibility with an older SQLite version.
@Fts4
@Entity(indices = {@Index(value = {"first_name", "last_name"},
        unique = true)})
public class User {
    // Specifying a primary key for an FTS-table-backed entity is optional, but
    // if you include one, it must use this type and column name.
    @PrimaryKey
    @ColumnInfo(name = "rowid")
    public int id;
​
    @ColumnInfo(name = "first_name")
    public String firstName;
}

2:创建数据访问对象

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();
​
    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);
​
    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
           "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);
​
    @Insert
    void insertAll(User... users);
​
    @Delete
    void delete(User user);
}

3:数据库对象创建

在实例化 AppDatabase 对象时应遵循单例设计模式因为每个 RoomDatabase 实例的成本相当高

对数据库单例的简单封装

@Database(entities = {User.class},version = 1)//指定版本号和数据库的实体类
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();//必须方法
​
​
    private static AppDatabase instance=null;
​
    public static  AppDatabase getInstance(Context context){
​
        if (instance==null){
            synchronized (AppDatabase.class) {
                if (instance==null) {
                    instance = Room.databaseBuilder(context, AppDatabase.class, "BDName").build();
                    //注意第一个参数一定要使用applicationContext,而不能使用普通的
//context,否则容易出现内存泄漏的情况
                }
            }
        }
        return instance;
​
    }
}

4:使用

UserDao userDao=AppDatabase.getInstance(getApplicationContext()).userDao();
List<User> all = userDao.getAll();

结合Rxjava

数据库也可以和RXjava 联合在一起使用(room数据库默认不能在主线程操作,但可以修改默认配置)

 Room.databaseBuilder(context, AppDatabase.class, "BDName").allowMainThreadQueries().build();//修改可以在主线程进行数据库操作

如果不修改默认配置且在主线程在数据库进行操作

  • 在正常情况下程序会crash
  • 在和rxjava一起使用时会在onError()方法中回调
User user=new User();
 user.setAge(10);
 user.setFirstName("h");
 user.setLastName("555");
 Completable completable=userDao.insertUser(user);
completable.
    subscribeOn(Schedulers.io()).
    observeOn(AndroidSchedulers.mainThread()).
    subscribe(new CompletableObserver() {
     @Override
     public void onSubscribe(@NonNull Disposable d) {
​
     }
​
     @Override
     public void onComplete() {
         Log.d("complete", "onComplete: ");
         Toast.makeText(MainActivity.this, "success", Toast.LENGTH_SHORT).show();
     }
​
     @Override
     public void onError(@NonNull Throwable e) {
         Toast.makeText(MainActivity.this, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
     }
 });

注意事项

如果想要从数据库中查询数据,或者使用非实体类参数来增删改数据,那么就必须编写 SQL语句

  • 删改

    Room 使用主键将传递的实体实例与数据库中的行进行匹配。如果没有具有相同主键的行,Room 不会进行任何更改。

    若要根据不同的情况也要写query语句

  • 插入方法的onConflict属性

@Insert(onConflict = OnConflictStrategy.REPLACE)
    public void insertUsers(User... users);

如果指定 id 的对象没有保存在数据库中, 就会新增一条数据到数据库。 如果指定 id 的对象数据已经保存到数据库中, 就会删除掉原来的数据, 然后新增一条数据。

  • 编写SQL语句进行查询

image-20220723164357040]()

参考 :第一行代码第三版

使用 Room 将数据保存到本地数据库 | Android 开发者 | Android Developers (google.cn)