Android Jetpack 之Room使用

1 篇文章 0 订阅
1 篇文章 0 订阅

Room

Room是Jetpack组件库一员,属于ORM库,Room 在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。

Room 包含 3 个主要组件:

  • Database: 你可以使用这个组件创建一个数据库holder。注解定义了一系列entities并且类的内容提供了一系列DAOs,它也是下层的主要连接 的访问点。Database注解的类应该是一个抽象的继承 RoomDatabase的类。在运行时,你能获得一个实例通过调用Room.databaseBuilder()或者 Room.inMemoryDatabaseBuilder()
  • Entity:这个组件代表了一个持有数据行的类。实际上也是一个bean类,对于每个entity,一个数据库表被创建用于持有items。你必须引用entity类通过Database类中的entities数组。每个entity字段被持久化为数据库中的列,使用@Ignore注解可以不添加到数据库中.
  • DAO:包含用于访问数据库的方法。DAOs 是Room中的主要组件,并且负责定义访问数据库的方法。被注解为@Database的类必须包含一个没有参数的抽象方法并且返回注解为@Dao的类。当在编译时生成代码,Room创建一个这个类的实现。

在这里插入图片描述
官网对三者的说明,可以清楚的看到它们的职责。

导入

在model的build.gradle中添加,androidx版本:

def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"

看到annotationProcessor就知道它肯定是用的APT技术替我们生成了一些文件。

使用

第一步,先新建一个bean类,因为我比较喜欢车,就命名为Car吧:

import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;

//默认表名为类名
@Entity(tableName = "cars")
public class Car {
    //主键
    @PrimaryKey(autoGenerate = true)
    //列名 _id
    @ColumnInfo(name = "_id")
    private int id;
    @ColumnInfo(name = "_brand")
    private String brand;
    //不指定类名 默认就是model
    private String model;
    @ColumnInfo(name = "_price")
    private int price;
	//后面的set get toString都省略不贴了
    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
    //set get .....

}

这个类需要用@Entity注解,tableName 就是表名,不加tableName 默认就是类名。而且需要添加到数据库中的字段需要时public,如果不用public修饰就需要提供set get方法。如果某个成员不需要添加到数据库中,可以使用@Ignore注解它。

第二步,然后创建一个Dao类:

import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.Update;
import java.util.List;

@Dao
public interface CarDao {
    //如果冲突--替换
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insetCar(Car... car);
    //查询所有的car
    @Query("SELECT * FROM cars")
    List<Car> getAll();
    //查询指定品牌的car
    @Query("SELECT * FROM cars WHERE _brand == :brand")
    List<Car> getBrand(String brand);
    //查询价格在min和max的car
    @Query("SELECT * FROM cars WHERE _price BETWEEN :min AND :max")
    List<Car> getCarBetweenPrices(int min,int max);
    //可以返回void 返回int代表删除了多少行
    @Delete
    int deleteCar(Car car);
    //更新 返回更新的个数
    @Update(onConflict = OnConflictStrategy.REPLACE)
    int updateCars(Car... cars);
}

CarDao就是对数据库的增删改查操作,这里就简单写了一些。

第三步,创建一个DataBase抽象类:

import androidx.room.Database;
import androidx.room.RoomDatabase;

@Database(entities = Car.class,version = 1)
public abstract class CarDatabase extends RoomDatabase {
    public abstract CarDao carDao();
}

entities:数据库相关的所有Entity实体类,他们会转化成数据库里面的表。version:数据库版本。运行时,通过调用Room.databaseBuilder()或者Room.inMemoryDatabaseBuilder()获取实例。因为每次创建Database实例都会产生比较大的开销,所以应该将Database设计成单例的,或者直接放在Application中创建。

  • Room.databaseBuilder()是创建一个存在文件系统中的数据库。
  • Room.inMemoryDatabaseBuilder():创建一个存在内存中的数据库。当应用退出的时候(应用进程关闭)数据库也消失。

接下来就是去操作数据库了,做了个简单的封装:

import android.content.Context;
import androidx.room.Room;
import java.util.List;
import honeywell.com.androidstudy.DataBase.room.Car;
import honeywell.com.androidstudy.DataBase.room.CarDao;
import honeywell.com.androidstudy.DataBase.room.CarDatabase;

public class CarMode implements ICarMode{

    private static volatile CarMode carMode;
    private CarDatabase carDatabase;
    private CarDao carDao;

    private CarMode(Context context) {
        //创建数据库
        carDatabase = Room.databaseBuilder(context,CarDatabase.class,"Car.db")
                .allowMainThreadQueries()
                .build();
        //获取到carDao
        carDao = carDatabase.carDao();
    }

    public static CarMode getInstance(Context context) {
        if (carMode == null) {
            synchronized (CarMode.class) {
                if (carMode == null){
                    carMode = new CarMode(context);
                }
            }
        }
        return carMode;
    }

    @Override
    public void addItem(Car car) {
        carDao.insetCar(car);
    }

    @Override
    public int deleteItem(Car car) {
        return carDao.deleteCar(car);
    }

    @Override
    public List<Car> queryAll() {
        return carDao.getAll();
    }

}

通过这个单利类就可以去操作数据了。
看下效果:
在这里插入图片描述
因为是学习Room数据库的,请忽略UI。在看下数据库:
在这里插入图片描述
在这里插入图片描述
因为model我们没有手动指定他的ColumnInfo,所以就是原来对象的属性名。

升级

假如我们需要把model的列名改成_model,先在Entity类中修改:

@ColumnInfo(name = "_model")
    private String model;

然后将版本号改成2:

@Database(entities = Car.class,version = 2)
public abstract class CarDatabase extends RoomDatabase {
    public abstract CarDao carDao();
}

然后运行时就会挂掉:

java.lang.RuntimeException: Unable to start activity ComponentInfo{honeywell.com.androitstudy/honeywell.com.androidstudy.DataBase.CarActivity}: java.lang.IllegalStateException: A migration from 1 to 2 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods.

因为还没提供迁移策略。

	//表名是从版本1升级到版本2的策略
    Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(SupportSQLiteDatabase database) {
            // 将旧表重命名cars_temp
            database.execSQL("ALTER TABLE cars RENAME TO cars_temp");
            //创建一个新表
            database.execSQL("CREATE TABLE IF NOT EXISTS `cars` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `_brand` TEXT, `_model` TEXT, `_price` INTEGER NOT NULL)");
            //将旧表中的数据插入新表
            database.execSQL("INSERT INTO cars SELECT `_id`,`_brand`,`model`,`_price` FROM cars_temp");
            //删除旧表
            database.execSQL("DROP TABLE cars_temp");
        }
    };

    private CarMode(Context context) {
        carDatabase = Room.databaseBuilder(context,CarDatabase.class,"Car.db")
                .allowMainThreadQueries()
                //添加Migrations
                .addMigrations(MIGRATION_1_2)
                .build();
        carDao = carDatabase.carDao();
    }

因为sqlite没有提供直接修改列名的方法,所以只能采用这种方法。其他比如加一列直接用alter table add column就行了,这里就不再演示了。下面是升级后的数据库,注意看model的列名:

在这里插入图片描述
此时已经改成了_model了,而且之前的数据依旧存在。

如果你有一个非常老的数据库版本为1,而现在线上最新的为4。当前我们已经定义了以下几种迁移:
版本1 —> 版本2
版本2 —> 版本3
版本3 —> 版本4
那么 Room 将会触发所有的迁移策略,一个接一个去执行。
另外 Room 可以处理夸版本更新:直接可以定义一个迁移,直接一步从版本1到版本4,从而使迁移的进程更快。这里就不再演示了。

关于Room数据库的使用就写这么多吧,希望对大家有所帮助,如果有需要看源码的同学可以留言。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值