为了账号安全,请及时绑定邮箱和手机立即绑定

google官方orm数据框架room开箱使用

标签:
Android

我在前天才得知2017年的IO大会官方搞了个android.arch.persistence,orm数据库框架room便在其列....

1. 相关链接以及引入依赖

官网对Room的描述:https://developer.android.com/training/data-storage/room/index.html

官网引入依赖的步骤:https://developer.android.com/topic/libraries/architecture/adding-components.html

TIM图片20171206162825.png
这里注意maven { url 'https://maven.google.com' }改成google()
别问我怎么知道的因为我踩坑了,依赖一直下不下来,后面看见了官方
android-architecture-components的项目demo(项目地址https://github.com/googlesamples/android-architecture-components)才知道的,google诚不欺我也

总结一下 引入依赖的步骤:

  1. 在项目根build.gradle 加入google()如下
    allprojects {
    repositories {
        jcenter()
        google()
    }
    }
  2. 在你的app的build.gradle的dependencies里面添加
    compile "android.arch.persistence.room:runtime:1.0.0"
    compile "android.arch.persistence.room:rxjava2:1.0.0"
    annotationProcessor "android.arch.persistence.room:compiler:1.0.0"

    1.0都发布了,你们确定不用嘛?

2. 引入后体积大小变化

我写了个hello world工程测试了一下
引用前debug.apk大小是1417kb
引入Room后debug.apk大小是2077kb
也就是相差660kb(还能够接受)
我引入了GreenDao后debug.apk大小是2067kb,相差650k,
结论:Room和GreenDao的物理体积是差不多的

3. Room和其他主流android ORM框架的性能对比

参见此文:https://github.com/AlexeyZatsepin/Android-ORM-benchmark
他的总结翻译过来如下:

译文:在Google I/O 2017上,一个有趣的解决方案是在Android操作系统上使用数据库的最佳方案。尽管有必要使用显式的sql请求,但是这个库非常方便,而且我个人也很喜欢它。在性能方面处于领先地位,所以我建议您选择这个特定的库。由于这个解决方案是由Google提交的,它很快就会变得流行起来,因此,找到解决方案的解决方案是没有问题的。

4. 关于混淆

貌似没看见官方给出混淆代码的参考就看见,官方sample中提了一个issue,链接如下:https://github.com/googlesamples/android-architecture-components/issues/37,有大佬写了混淆的求指点一下~

5. Room 使用相关要点(占坑-。- 有空再更)
  1. @Entity注解修饰的类是表,非static成员变量,如果不加上@Ignor注解默认编译后将被生成到表里面
    (修改该类,比如加非static成员变量必须加上Migration代码视作一次数据库升级,不然报错),私有非静态成员变量必须添加get/set方法不然报错,当存在多个构造方法时,room会选择一个无参的构造方法(一般给列名参数不全的构造方法上面加@Ignor,因为查询返回表对象时候数据全一点),存在其他构造方法不带@Ignor注解,编译后会给出警告

  2. @Database注解修饰的类是数据文件实体,必须是抽象的同时要继承RoomDatabase
    必须要提供一个抽象方法返回值是DAO接口的实例类型

  3. @Dao注解修饰的类是DAO,它必须是个接口类,提供带有@Query查找以及删除方法的修饰注解(后面带sql语句,google在studio中提供了关键字高亮,很Nice),@Update更新方法的修饰注解,@Insert插入方法的修饰注解。

  4. @Database注解修饰的数据库实体抽象类,以及被被@Dao注解修饰的DAO接口类,在编译之后,会在你的app目录/build/generated/source/apt/debug/你的应用包名
    目录下面生成DAO接口类名_Impl类(生成接口中增删改查的具体方法)和数据库实体抽象类名_Impl的类(生成表的具体方法,以及生成一个该版本对应的identityHash字符串),在app的build.gradle文件defaultConfig节点内部添加

    // Write out the current schema of Room
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }

    会在目标目录下生成数据库版本变化的json文件(如果没有这个配置,编译后会给出相关警告)

  5. Room数据操作不能在主线程执行(不然运行时异常)

  6. 简单的初始化以及增删改查运用demo详见官方sample(https://github.com/googlesamples/android-architecture-components
    )中
    PersistenceContentProviderSample(Cheese类,CheeseDao类,以及SampleDatabase代码以及其使用),数据库版本升级的demo详见官方sample中PersistenceMigrationsSample(UsersDatabaseMigration的使用)

除了官方demo,具体的一些增删改查的操作别人已经写的很好了,我在这里就抛砖引玉,放上链接http://www.jianshu.com/p/c0c91f4226a6感谢原作者的分享,0.0居然是图乐大佬的简书

这里比较进阶的东西就是@TypeConverter,因为数据库基础类型并不会支持java的类型,比如

// THIS IS CAUSING THE ERROR... BASICALLY IT ISN'T READING ARRAYS
   @ColumnInfo(name = "mylist_array")
    private ArrayList<MyListItems> myListItems;

详细问题参见:https://stackoverflow.com/questions/44986626/android-room-database-how-to-handle-arraylist-in-an-entity
就是有时候查询出一个表对象实体的时候,我们想让某一列的数据是一个
ArrayList<MyListItems>类型,可说数据库不支持呀,还会报错,怎么办呢,这时候就需要@TypeConverter,stackoverflow链接中给出的

public class Converters {
@TypeConverter
public static ArrayList<String> fromString(String value) {
    Type listType = new TypeToken<ArrayList<String>>() {}.getType();
    return new Gson().fromJson(value, listType);
}

@TypeConverter
public static String fromArrayList(ArrayList<String> list) {
    Gson gson = new Gson();
    String json = gson.toJson(list);
    return json;
}
}

算是比较通用的方案了。
@TypeConverter的使用官方demo也提及了,可以看PersistenceMigrationsSample的DateConverter类在哪里被使用的,就能知道怎么使用了。

这里简单说一下:
以官方sample代码为例:
初始化数据库以及表
以下代码来自PersistenceContentProviderSample项目的SampleDatabase类

    public static synchronized SampleDatabase getInstance(Context context) {
        if (sInstance == null) {
            sInstance = Room
                    .databaseBuilder(context.getApplicationContext(), SampleDatabase.class, "ex")
                    .build();

            sInstance.populateInitialData();
        }
        return sInstance;
    }

SampleDatabase.class 继承自RoomDatabase@Database注解修饰的数据库实体抽象类,ex是数据库文件的名称,sInstance是一个SampleDatabase数据库实例的单例对象,执行了build之后如果不存在该数据库文件将会创建并返回一个数据库对象,如果存在数据库文件则直接返回数据库对象,我们再来看看populateInitialData干了什么

 private void populateInitialData() {
        if (cheese().count() == 0) {
            Cheese cheese = new Cheese();
            beginTransaction();
            try {
                for (int i = 0; i < Cheese.CHEESES.length; i++) {
                    cheese.name = Cheese.CHEESES[i];
                    cheese().insert(cheese);
                }
                setTransactionSuccessful();
            } finally {
                endTransaction();
            }
        }
    }

cheese()是SampleDatabase抽象数据库类必须有的返回值为一个DAO接口的方法,用以拿到DAO实现类对象,这里cheese().count()就是查询某个表的数据的总数,count()代码在PersistenceContentProviderSample项目的CheeseDao类

/**
     * Counts the number of cheeses in the table.
     *
     * @return The number of cheeses.
     */
    @Query("SELECT COUNT(*) FROM " + Cheese.TABLE_NAME)
    int count();

当执行到count()的时候最终会执行android api22的SQLiteOpenHelper类getDatabaseLocked方法(增删改查都会执行到该方法),这时候做了一些操作,以下代码是android api22的SQLiteOpenHelper类

 try {
                    if (version == 0) {
                        onCreate(db);
                    } else {
                        if (version > mNewVersion) {
                            onDowngrade(db, version, mNewVersion);
                        } else {
                            onUpgrade(db, version, mNewVersion);
                        }
                    }
                    db.setVersion(mNewVersion);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }

如果版本为0就会去创建表,否则要么执行升级代码,要么执行降级代码(一般数据库降级就抛异常)

以首次版本为0来说,接着就会调用Room api的RoomOpenHelper类的onCreate代码

@Override
    public void onCreate(SupportSQLiteDatabase db) {
        updateIdentity(db);
        mDelegate.createAllTables(db);
        mDelegate.onCreate(db);
    }

mDelegate是什么鬼呢,就是Room api的RoomOpenHelper类的Delegate类型
private final Delegate mDelegate;
我们看到mDelegate.createAllTables(db);这一行代码
最后是由

TIM图片20171207161013.png
执行的,也就是由apt自动生成的代码执行的,这一步之后表就有了。

  1. 官方给出demo的build_versions.min_sdk = 14,说明api14(android 4点几)也是支持哒

  2. 当如果查询结果是一个left join的时候呢,这时原来表对象就装不下了呀,怎么办呢(参考https://www.captechconsulting.com/blogs/android-architecture-components-room-persistence-library),或者,查询结果是对象的子集字段处理方式其实可以在官方demo 项目PersistenceMigrationsSample编译后apt目录下生成的UserDao_Impl类的getUser()方法代码中找到灵感
点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
1万
获赞与收藏
137

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消