带大家熟悉Android全新的Room数据库框架

最近Android推出全新的数据库框架Room,它与GreenDAO相似,基于ORM对象关系映射,属于轻量级且快速的数据库。对SQLite语句封装成了对象,也就意味着我们可以直接操作对象,是我们熟悉的对象。

Room基于SQLite,提供一个抽象层,可以快速访问SQLite的所有功能。应用程序处理特殊的结构化数据,可以极大程度受益于本地数据的持久化。大多数使用场景是缓存关联的数据块。那样,尽管设备无法联网,用户仍然可以在离线时查阅数据。任何用户初始化内容,一旦发生改变,会在设备联网后同步到服务器。Room框架如下图:

Room有3大组件:

Database:包含数据库持有者,并且作为应用程序持久关系数据的底层连接主要访问点。

       使用 @Database注解,需要满足以下条件:

       继承RoomDatabase的抽象类;

       在注解时,包含与数据库关联的entity集合;

       包含抽象方法,无参数,返回值是使用@Dao注解的类;

在运行时,你可以调用Room.databaseBuilder() 或者 Room.inMemoryDatabaseBuilder()来获取Database的实例。

Entity:代表数据库的表,使用@Entity注解;

DAO:包含数据库访问的增删查改方法,注解方法包括@Insert、@Update、@Query、@Delete;

用法比较简单,在gradle添加依赖:

    implementation "android.arch.persistence.room:runtime:1.1.1"
    annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
    implementation "android.arch.persistence.room:rxjava2:1.1.1"
    implementation "android.arch.persistence.room:testing:1.1.1"

定义一个抽象类,继承于RoomDatabase,在获取Database实例时,构造数据库:

    private static AppDatabase buildDatabase(final Context appContext,
            final AppExecutors executors) {
        return Room.databaseBuilder(appContext, AppDatabase.class, DATABASE_NAME)
                .addCallback(new Callback() {
                    @Override
                    public void onCreate(@NonNull SupportSQLiteDatabase db) {
                        super.onCreate(db);

                    }
                }).build();
    }

定义一个接口model,比如一个product产品:

public interface Product {
    int getId();
    String getName();
    String getDescription();
    int getPrice();
}

定义一张表,使用@Entity进行注解,声明id作为主键:

@Entity(tableName = "products")
public class ProductEntity implements Product {
    @PrimaryKey
    private int id;
    private String name;
    private String description;
    private int price;

    @Override
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
    
    public ProductEntity(int id, String name, String description, int price) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.price = price;
    }

}

定义一个DAO,实现增删查改方法:

@Dao
public interface ProductDao {
    //插入单个对象,发生冲突时就替换原来的
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertProduct(ProductEntity product);
    //插入对象列表
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertAll(List<ProductEntity> products);
    //根据id查询对象
    @Query("select * from products where id = :productId")
    ProductEntity loadProduct(int productId);
    //查询整张表
    @Query("SELECT * FROM products")
    List<ProductEntity> loadAllProducts();
    //更新指定对象
    @Update
    void updateProduct(ProductEntity product);
    //删除指定对象
    @Delete
    void deleteProduct(ProductEntity product);
}

插入对象,数据库增删查改操作都需要在非UI线程执行,也就是开启子线程执行:

    private void insert(){
        RoomApplication.getInstance().getExecutors().diskIO().execute(() -> {
            List<ProductEntity> productList = new ArrayList<>();
            ProductEntity product1 = new ProductEntity(1, "apple", "very tasty", 10);
            productList.add(product1);
            ProductEntity product2 = new ProductEntity(2, "grape", "very very tasty", 10);
            productList.add(product2);
            appDatabase.productDao().insertAll(productList);
        });
    }

需要查询整张表时,可以这样操作:

    private void query(){
        RoomApplication.getInstance().getExecutors().diskIO().execute(() -> {
            List<ProductEntity> productList = appDatabase.productDao().loadAllProducts();
            if (productList != null && productList.size() > 0){
                for (ProductEntity productEntity:productList){
                    Log.e(TAG, "name = " + productEntity.getName());
                    Log.e(TAG, "description=" + productEntity.getDescription());
                }
            }
        });
    }

更新指定对象:

    private void update(){
        RoomApplication.getInstance().getExecutors().diskIO().execute(() -> {
            ProductEntity product = new ProductEntity(1, "apple", "very tasty and sweet", 20);
            appDatabase.productDao().updateProduct(product);
        });
    }

删除指定对象:

    private void delete(){
        RoomApplication.getInstance().getExecutors().diskIO().execute(() -> {
            ProductEntity product = new ProductEntity(2, "grape", "very very tasty", 10);
            appDatabase.productDao().deleteProduct(product);
        });
    }

关于Room数据库升级,可以写Migration类来实现升级。在运行期,Room会运行每个Migration类的migrate()方法,把旧版本的数据库迁移到新版本。例如,数据库1.2版本升级到1.3版本,在表中增加字段:

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 `Product` (`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 Product"
                + " ADD COLUMN pub_year INTEGER");
    }
};

关于Room数据库测试,推荐编写JUnit测试单元,运行在Android设备上,进行数据库的测试。单元测试示例:

@RunWith(AndroidJUnit4.class)
public class SimpleEntityReadWriteTest {
    private UserDao mUserDao;
    private TestDatabase mDb;

    @Before
    public void createDb() {
        Context context = InstrumentationRegistry.getTargetContext();
        mDb = Room.inMemoryDatabaseBuilder(context, TestDatabase.class).build();
        mUserDao = mDb.getUserDao();
    }

    @After
    public void closeDb() throws IOException {
        mDb.close();
    }

    @Test
    public void writeUserAndReadInList() throws Exception {
        User user = TestUtil.createUser(1);
        user.setName("frank");
        mUserDao.insert(user);
        List<User> byName = mUserDao.findUsersByName("frank");
        assertThat(byName.get(0), equalTo(user));
    }
}

关于Room中使用复杂数据类型,可以使用TypeConverter进行数据类型转换。例如,我们希望持有Date的实例,我们可以写一个TypeConverter来存储一个相等的Unix时间戳:

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

看到这里,大家应该对Room数据库框架有深刻认识与理解,可以开启全新的数据库之旅了,结合LifeCycle使用那就更加灵活。

Demo地址:https://download.csdn.net/download/u011686167/10684169

发布了63 篇原创文章 · 获赞 179 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/u011686167/article/details/82826364