简单快速的对象存储库:Paper(一)
在GitHub上淘宝,最近又发现一个设计精巧而简单快速的存储库:Paper,可以考虑用来替代Preference。另一位牛人César Ferreira基于Paper,结合RxJava写了一个RxPaper2。
GitHub:https://github.com/pilgr/Paper
1、Paper
Paper,正如其名:此库旨在让开发者存储对象数据,犹如在纸上写字一样轻而易举。
1.1、简介
“Paper 的目标是为 Android 提供一个简单而快速的对象存储选项。 它允许按原样使用 Java/Kotlin 类:没有注释、工厂方法、强制类扩展等。此外,向数据类添加或删除字段不再是一件痛苦的事——所有数据结构更改都将自动处理。”
在性能,易用性各方面都要相比同类型的库要强。
1.2、引入Paper库
项目中引入Paper库,只需在模块的build.gradle中加上:
dependencies {
...
//https://github.com/pilgr/Paper
implementation 'io.github.pilgr:paperdb:2.7.2'
}
2、Paper快速上手
Paper库本身的源码很少,得益于其简洁的设计,使用非常起来很方便。有一点要注意,除了初始化操作可以放在UI线程,其它所有操作(插入、查询等等)都要放在子线程中,因为都涉及到对文件的读写操作。不过不用担心,所有的操作都是线程安全的,对同一个键的读写可以并行。
2.1、初始化
在重写应用Application的onCreate()方法中初始化Paper库:
@Override
public void onCreate() {
super.onCreate();
//初始化Paper
Paper.init(this);
}
先看一下这里的源码,非常轻量的操作:只是初始化一下内部的Context对象将其赋值为全局Application,后面获取应用的文件目录时会用到。
/**
* Lightweight method to init Paper instance. Should be executed in {@link Application#onCreate()}
* or {@link android.app.Activity#onCreate(Bundle)}.
*
* @param context context, used to get application context
*/
public static void init(@NonNull Context context) {
mContext = context.getApplicationContext();
}
2.2、插入 write
插入一条数据非常简单,两个参数:String类型的键,任意类型的值。不过值也不要太随意:如Activity这样的重对象,或者含有循环引用的对象实测无法存储。
可以指定“书”名name(目录名)和“书”放置的位置position(目录路径)。向此“书”中写入几个键值,再次写入就是更新键对应的值。对于保存的类对象,当类内部新增或删除字段时,Paper能够自动兼容,但如果字段类型发生改变就没办法了。
//默认位置,指定Book名称
Paper.book("cn.quibbler").write("number", 10058);
//指定位置,默认Book名称
Paper.bookOn(Environment.getExternalStorageDirectory().getPath()).write("name", "Quibbler");
//指定保存位置和Book名称
Paper.bookOn("/sdcard/file/info", "cn.quibbler").write("info", new Info());
若不指定“书”名,默认“书”名是io.paperdb,这也是内部保留名称。
Paper.book().write("number", 10058);
Paper.book().write("name", "Quibbler");
Paper.book().write("info", new Info());
其实此“书”名就是保存键值文件的文件夹目录名,还可以指定目录的存储位置,后面看源码就会明白。
2.3、查询 read
使用read(String key)根据key查找Book中的值:
Integer number = Paper.book().read("number");
//查找键值
String name = Paper.book().read("name");
//从"cn.quibbler"书中查找键所对应的值
Info info = Paper.book("cn.quibbler").read("info");
如果查不到就会返回null,可以提供一个默认值,在没有对应值的时候返回默认值:
//查找number对应的值,若不存在返回-1
Integer number = Paper.book().read("number", -1);
//查找name键对应的值,若没有返回default
String name = Paper.book().read("name", "defalut");
使用Book的getAllKeys()方法返回此“书”中保存的所有键的集合:
//查询默认Book中存储的全部键值
List<String> keys = Paper.book().getAllKeys();
//查询"cn.quibbler"中的全部键值,其实也就是此目录下的全部文件名
List<String> keys = Paper.book("cn.quibbler").getAllKeys();
使用contains(String key)方法查询是否存储了对应键:
boolean hasInfo = Paper.book().contains("info");
2.4、删除 delete
有插入就有删除,使用Book的delete(String key)方法删除键值:
Paper.book().delete("name");
Paper.book("cn.quibbler").delete("info");
3、Paper原理
这里先简单了解一下它的设计思路:对于每个Book都是一个独立的文件目录,key是该目录下的文件名(不含.pt后缀),而value则是保存在文件中序列化的内容。
看一下/data/data/应用的目录结构,不同的Book对应各不同的目录,目录下的文件就是存储在当前“书”上的键值。
Paper的源码精练(不算上引用的另一个Kryo库,只有516行),设计简单、结构清晰,代码简洁的典范。
详见简单快速的对象存储库:Paper(二)一文。