2021-07-01

Android ROOM的基本使用

简介

room持久层提供一个SQLite的抽象层
Room不是数据库,只是对Sqlite做了一个改造
Room 是一个对象关系映射(ORM)库。可以很容易将 SQLite 表数据转换为 Java 对象。Room 在编译时检查 SQLite 语句。
Room 为 SQLite 提供一个抽象层,以便在充分利用 SQLite 的同时,可以流畅地进行数据库访问。

导入依赖

dependencies {
def room_version = “1.1.1”

implementation "android.arch.persistence.room:runtime:$room_version"
annotationProcessor "android.arch.persistence.room:compiler:$room_version" // use kapt for Kotlin

// optional - RxJava support for Room
implementation "android.arch.persistence.room:rxjava2:$room_version"

// 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"

}

ROOM的三个重要组件

在使用数据的时候,需要主要涉及到Room三个部分:

  • Entity: 数据库中表对应的实体
  • DataBase: 创建数据库实例
  • Dao: 操作数据库的方法

第一步 创建实体类

import android.graphics.Bitmap;

import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;

import java.util.Date;

/**
 1. 播放记录
 */
//创建一个实体Entity playRecord,在注释中包含数据库相关联的实体列表
@Entity(tableName = "play_record")//数据库的表名
public class PlayRecord {

    // 有些情况下,需要主键是自增的,可以配置属性autoGenerate=true来实现。
//    @PrimaryKey(autoGenerate = true)
//    @ColumnInfo(name = "_id")
//    private int id;

    /**
     * 文件地址
     */
    @PrimaryKey()//主键自增
    @NonNull

    private String url;

    /**
     * 播放位置
     */

    private int position;

    /**
     * 记录时间
     */
    @ColumnInfo(name = "update_time")//在表中对应的字段名,updateTime是该对象中的变量
    private Date updateTime;

    //设置忽略字段
    @Ignore
    Bitmap picture;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
}
  • @Entity: 代表一个表中的实体,默认类名就是表名,如果不想使用类名作为表名,可以给注解添加表名字段
  • @Entity(tableName = “user”)
  • @PrimaryKey: 每个实体都需要自己的主键
  • @NonNull 表示字段,方法,参数返回值不能为空
  • @ColumnInfo(name = “faceId”) 如果希望表中字段名跟类中的成员变量名不同,添加此字段指明

第二步 创建Dao



import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;

import com.group10.myapplication.room.entity.PlayRecord;

import java.util.List;

//写入方法,增删改查 url查询地址,带参数
@Dao
public interface PlayRecordDao {

    @Insert
    long insert(PlayRecord record);

    @Update
    int update(PlayRecord record);

    @Delete
    int delete(PlayRecord record);

    @Query("DELETE FROM play_record WHERE url = :url")
    int deleteByUrl(String url);

    @Query("SELECT * FROM play_record")
    List<PlayRecord> queryAll();

    @Query("SELECT * FROM play_record WHERE url IN (:urls)")
    List<PlayRecord> queryByUrls(List<String> urls);

    @Query("SELECT * FROM play_record WHERE url = :url")
    PlayRecord queryByUrl(String url);

}

DAO是数据访问对象,指定SQL查询,并让他与方法调用相关联。
DAO必须是一个接口或者抽象类。
默认情况下,所有的查询都必须在单独的线程中执行

第三步 创建Database


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

import com.group10.myapplication.room.converter.Converters;
import com.group10.myapplication.room.dao.PlayRecordDao;
import com.group10.myapplication.room.entity.PlayRecord;

//创建数据库类dateBase
//在room持久库中,通过@Datebase类来访问数据库,注释定义数据库类,entities指明包含的实体
//version 表示版本
@Database(entities = {PlayRecord.class}, version = 1, exportSchema = false)
@TypeConverters(Converters.class)
public abstract class AppDatabase extends RoomDatabase {
    /**
     * 获取一个播放列表的操作对象
     *
     * @return
     */
    public abstract PlayRecordDao playRecordDao();
}
  • 创建一个抽象类继承自appDatabase

  • 给他添加一个注解@Database表名它是一个数据库,注解有两个参数第一个是数据库的实体,它是一个数组,可以传多个,当数据库创建的时候,会默认给创建好对应的表,第二个参数是数据库的版本号

  • 定义跟数据库一起使用的相关的DAO类

  • 创建一个RoomDemoDatabase的单例,防止同时打开多个数据库的实例

  • 使用Room提供的数据库构建器来创建该实例,第一个参数application,第二个参数当前数据库的实体类,第三个参数数据库的名字

第四步,获取播放记录操作对象


/**
 * 一个工具类:用于获取各种数据库句柄
 */
public class DatabaseHelper {

    /**
     * 数据库名称
     */
    public static final String DATABASE_NAME = "video_player";

    //单例模式,保证获取的数据库实例是唯一的
    private static AppDatabase AppDatabase;

    //数据库版本号
    private static final int DATABASE_VERSION = 1;


    /**
     * 获取播放记录操作对象
     * 获得接口的对象在主线程运行
     * @param context
     * @return
     */

    public static PlayRecordDao getPlayRecordDao(Context context) {
        AppDatabase db = Room
                .databaseBuilder(context, AppDatabase.class, DATABASE_NAME)
                .allowMainThreadQueries() // 运行在主线程执行
                .build();
        return db.playRecordDao();
    }
}

第五步 类型转换

当字段为空的时候,数据库会crash,报错信息是说“数据库不可为空的字段为空”,实际上对比sql语句,发现所有的not null字段全部是有值的。

原因是使用了TypeConverter,上面的代码中的转换方式会导致photo字段被系统认为是not null字段了

要解决这个问题,要改为以下这样,入参和返回值都要加?,这样系统认为这个字段是可为空的


import androidx.room.TypeConverter;

import java.util.Date;
//类型转换long类型转换成date类型,进行存储。date类型转换成long
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();
    }
}


第六步 新增或更新播放记录


    @Override
    public void onBackPressed() {
        if (vgContainerFullScreen.indexOfChild(vVideoArea) != -1) {
            fullScreen(false);
        } else {
            // 新增或更新播放记录
            try {
                if (null != mp && mp.isPlaying()) {
                    PlayRecord playRecord = new PlayRecord();
                    playRecord.setUrl(mediaInfos.get(currentIndex).getUrl());
                    playRecord.setPosition(mp.getCurrentPosition());
                    playRecord.setUpdateTime(new Date());
                    playRecordService.insertOrUpdate(playRecord);
                }
            } catch (Exception e) {
                Log.e(TAG, "playByIndex: ", e);
            }
            super.onBackPressed();
        }
    }
上一篇:android----Room数据库的操作(2)


下一篇:Github PullRequest 示例