1. 相关链接以及引入依赖我在前天才得知2017年的IO大会官方搞了个android.arch.persistence,orm数据库框架room便在其列....
官网对Room的描述:https://developer.android.com/training/data-storage/room/index.html
官网引入依赖的步骤:https://developer.android.com/topic/libraries/architecture/adding-components.html
这里注意maven { url 'https://maven.google.com' }
改成google()
别问我怎么知道的因为我踩坑了,依赖一直下不下来,后面看见了官方
android-architecture-components的项目demo(项目地址https://github.com/googlesamples/android-architecture-components)才知道的,google诚不欺我也
总结一下 引入依赖的步骤:
- 在项目根build.gradle 加入
google()
如下allprojects { repositories { jcenter() google() } }
- 在你的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都发布了,你们确定不用嘛?
我写了个hello world工程测试了一下
引用前debug.apk大小是1417kb
引入Room后debug.apk大小是2077kb
也就是相差660kb(还能够接受)
我引入了GreenDao后debug.apk大小是2067kb,相差650k,
结论:Room和GreenDao的物理体积是差不多的
参见此文:https://github.com/AlexeyZatsepin/Android-ORM-benchmark
他的总结翻译过来如下:
4. 关于混淆译文:在Google I/O 2017上,一个有趣的解决方案是在Android操作系统上使用数据库的最佳方案。尽管有必要使用显式的sql请求,但是这个库非常方便,而且我个人也很喜欢它。在性能方面处于领先地位,所以我建议您选择这个特定的库。由于这个解决方案是由Google提交的,它很快就会变得流行起来,因此,找到解决方案的解决方案是没有问题的。
貌似没看见官方给出混淆代码的参考就看见,官方sample中提了一个issue,链接如下:https://github.com/googlesamples/android-architecture-components/issues/37,有大佬写了混淆的求指点一下~
5. Room 使用相关要点(占坑-。- 有空再更)-
被
@Entity
注解修饰的类是表,非static成员变量,如果不加上@Ignor注解默认编译后将被生成到表里面
(修改该类,比如加非static成员变量必须加上Migration
代码视作一次数据库升级,不然报错),私有非静态成员变量必须添加get/set
方法不然报错,当存在多个构造方法时,room会选择一个无参的构造方法(一般给列名参数不全的构造方法上面加@Ignor,因为查询返回表对象时候数据全一点),存在其他构造方法不带@Ignor注解,编译后会给出警告 -
被
@Database
注解修饰的类是数据文件实体,必须是抽象的同时要继承RoomDatabase
必须要提供一个抽象方法返回值是DAO接口的实例类型 -
被
@Dao
注解修饰的类是DAO,它必须是个接口类,提供带有@Query
查找以及删除方法的修饰注解(后面带sql语句,google在studio中提供了关键字高亮,很Nice),@Update
更新方法的修饰注解,@Insert
插入方法的修饰注解。 -
被
@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文件(如果没有这个配置,编译后会给出相关警告)
-
Room数据操作不能在主线程执行(不然运行时异常)
- 简单的初始化以及增删改查运用demo详见官方sample(https://github.com/googlesamples/android-architecture-components
)中
PersistenceContentProviderSample(Cheese
类,CheeseDao
类,以及SampleDatabase
代码以及其使用),数据库版本升级的demo详见官方sample中PersistenceMigrationsSample(UsersDatabase
类Migration
的使用)
除了官方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);
这一行代码
最后是由
执行的,也就是由apt自动生成的代码执行的,这一步之后表就有了。
-
官方给出demo的
build_versions.min_sdk = 14
,说明api14(android 4点几)也是支持哒 - 当如果查询结果是一个left join的时候呢,这时原来表对象就装不下了呀,怎么办呢(参考https://www.captechconsulting.com/blogs/android-architecture-components-room-persistence-library),或者,查询结果是对象的子集字段处理方式其实可以在官方demo 项目PersistenceMigrationsSample编译后apt目录下生成的UserDao_Impl类的
getUser()
方法代码中找到灵感
共同学习,写下你的评论
评论加载中...
作者其他优质文章