Android 中使用 Room 实践

使用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 打开查看。

    原文作者:YueGs
    原文地址: https://www.jianshu.com/p/82ba6c700397
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞