美文网首页数据库
Android 中使用 Room 实践

Android 中使用 Room 实践

作者: 风雪围城 | 来源:发表于2017-12-26 22:27 被阅读929次

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

    相关文章

      网友评论

        本文标题:Android 中使用 Room 实践

        本文链接:https://www.haomeiwen.com/subject/hnargxtx.html