使用Room进行持久化存储—综述
通过 Room entities 定义数据 —Room 系列(1)
使用 Room 的 DAO 访问数据—Room 系列(2)
前面讲述了 Room 库的一些概念,这里记录一下自己的实践部分。
0. 添加依赖
implementation "android.arch.persistence.room:runtime:1.0.0"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
1. 设置 Schema 的位置
在开始使用的时候,并没有注意 Schema 的问题,所以它就抛出了警告,希望我们指定 Schema 的输出位置,以更好的表明数据库的结构信息。这是,你需要在 build.gradle 中添加:
defaultConfig {
applicationId "com.yuegs.test"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
multiDexEnabled true
//********注意这里**********
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
//*************************
}
}
......
}
然后,编译运行之后,你就可以看到工程目录下的 schemas 问价夹。
每个数据库,会对应一个自己的 schema。
打开文件夹里面的 json 文件,你就能清楚看到自己定义的由Room 实际完成的数据库 schema 了。
2. 在数据库中存图片
遇到的第一个问题,就是如何使用 Room 库在数据库中存储图片。虽然,在数据库中存储图片实际上一般是不推荐的,但是还要看具体的使用场景和需求。
比如,我的需求主要来源于:将图片从服务器下载之后,持久化存储到本地;图片主要是一些勋章图片,大小在50k下;在需要的时候,需要快速检索出图片然后显示给用户;存储的时候,还需要记录图片的md5、勋章名称等。查了下资料,SQLite 可以存储的内容,在 TB 量级上,所以不需要担心数据库存不下你的内容,只要磁盘空间足够,就不存在问题。 (我使用模拟器,测试插入了1万张图片,在插入6千多图片后,大约2G,因为模拟器磁盘空间不足而抛出异常)。
@Entity
class User {
@PrimaryKey(autoGenerate = true)
public int id;
public String firstName;
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
private byte[] headImage;
}
使用数据库存储图片,和直接在存储卡上存储文件相比,肯定往往不如直接存储文件效率高(文件搜索查询功能非常单纯),然而,数据库中存储了更多的结构性信息。
最后,为了以防万一,还是把图片再处理下,使用 OkHttp 下载图片,处理,插入数据库:
OkHttpUtils.get(url, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
byte [] data = response.body().bytes() ;
//以 50k 作为基准,50k以内不做处理,大于50k时,将压缩到50-100k之间
float compressTimes = data.length / 1024.0f /50 ;
ByteArrayOutputStream baos ;
Bitmap bitmap ;
if(compressTimes > 1){
baos = new ByteArrayOutputStream();
bitmap = BitmapFactory.decodeByteArray(data,0,data.length) ;
bitmap.compress(Bitmap.CompressFormat.JPEG, Math.round(100 /compressTimes), baos);
data = baos.toByteArray();
}
User user1 = new User();
user1.setFirstName("compress");
user1.setImage(data);
db.userDao().insertAll(user1);
}
});
3. 将引用类型转换为基础类型存储
在 Room 中,是不支持引用类型的存储的(主要考虑到效率问题,往往我们在查询的时候想要查出的内容仅仅是一个属性,而不是一个对象),那么,我想存储时间 Date ,该怎么办呢?
需要提供一种转换,将引用类型转换为它可以存储的基础类型。
public class DateConverter {
@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();
}
}
上述代码块 ,将 Date 类型数据,转换为 long 类型的数据,可以存储在数据库中。
转换方法写完了,下面需要告诉数据库这个转换方法,否则它仍然无法完成转换,会报错告诉你它无法识别这个类型。
@Database(entities = { LogEntity.class},version = 1)
@TypeConverters({DateConverter.class})
public abstract class LogDatabase extends RoomDatabase {
public abstract LogDao logEntityDao() ;
}
如上述代码块所示,在数据库上添加 @TypeConverters 注解。
4. 数据库导出与查看
我是在模拟器(系统4.4)中做的测试,那么直接使用 Android Studio 将数据库文件导出,使用 SQLite Expert 打开查看。