【Android】LitePal安装和使用
本文基本上为整理稿。感谢LitePal的作者和郭霖大神。
参考文献:
Github — https://github.com/LitePalFramework/LitePal
《LitePal 1.6.0版本来袭,数据加解密功能保障你的应用数据安全》— https://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA%3D%3D&mid=2650240766&idx=1&sn=096f029aa531d5d99191c3d4c9126fc1#wechat_redirect
Tag:ORM
,Android
、LitePal
[TOC]
关于LitePal
LitePal是一个可以让开发者更简单操作SQLite的开源Android库。你不用写SQL命令就可以完成大部分诸如创建或更新表、CRUD操作和聚合函数等数据库操作。LitePal的安装也十分简单,不用5分钟就可以集成到你的项目中。
特性
- 使用对象关系映射(ORM)设计模式;
- 几乎零配置(仅仅配置一个很少属性的配置文件);
- 自动维护所有的表(比如:创建表、修改表和删除表);
- 多数据库支持;
- 为避免写SQL语句而封装了APIs;
- 极为流畅的查询API;
- 仍然还可以选择使用SQL,但APIs要比原生的更好更容易。
安装
导入库
在AndroidStudio中,编辑build.gradle
文件,加入以下:
dependencies {
compile 'org.litepal.android:core:1.6.0'
}
配置litepal.xml
在项目中的assets
文件下,创建并命名一个litepal.xml
文件,并编辑修改为以下代码:
将加密数据库存储在SD卡
如果需要将加密后的数据库保存到SD卡上,则需要修改litepal.xml
中的配置。代码如下:
注意:不需要填写SD卡的完成路径,需要配置相对路径即可。
由于LitePal中既没有Activity也没有Fragment,所以LitePal是不会去帮你申请运行时的SD卡访问读写权限。如果选择将数据库文件存储在SD卡上,请一定要确保你的应用程序已经对访问SD卡权限进行了运行时权限处理,否则LitePal的所有操作都将会失败。
配置LitePalApplication
配置AndroidManifest.xml
如下:
当然,还有一种配置方法。
public class MyOwnApplication extends xxxApplication {
@Override
public void onCreate() {
super.onCreate();
LitePal.initialize(this);
}
}
注意:最好是在
onCreate()
方法中进行初始化LitePal.initialize(this)
。
使用
创建表
比如,有两个模型类:【专辑】和【歌曲】。定义模型如下:
public class Album extends DataSupport {
@Column(unique = true, defaultValue = "unknown")
private String name;
private float price;
private byte[] cover;
private List songs = new ArrayList();
// generated getters and setters.
}
public class Song extends DataSupport {
@Column(nullable = false)
private String name;
private int duration;
@Column(ignore = true)
private String uselessField;
private Album album;
// generated getters and setters.
}
然后,在litepal.xml
文件中添加这两个模型的映射列表。
这样,当进行数据库操作的时候,会自动生成表。例如:
SQLiteDatabase db = LitePal.getDatabase();
自动生成的表,等价于以下SQLs:
CREATE TABLE album (
id integer primary key autoincrement,
name text unique default 'unknown',
price real,
cover blob
);
CREATE TABLE song (
id integer primary key autoincrement,
name text not null,
duration integer,
album_id integer
);
更新表
例如添加一个发布时间字段并注释掉【售价】字段:
public class Album extends DataSupport {
@Column(unique = true, defaultValue = "unknown")
private String name;
@Column(ignore = true)
private float price;
private byte[] cover;
private Date releaseDate;
private List songs = new ArrayList();
// generated getters and setters.
}
litepal.xml
文件中的数据库版本会自动进行更新。
保存数据
保存操作的API是面向对象的。每个继承于DataSupport
的模型都有save()
方法。例如:
Album album = new Album();
album.setName("album");
album.setPrice(10.99f);
album.setCover(getCoverImageBytes());
album.save();
Song song1 = new Song();
song1.setName("song1");
song1.setDuration(320);
song1.setAlbum(album);
song1.save();
Song song2 = new Song();
song2.setName("song2");
song2.setDuration(356);
song2.setAlbum(album);
song2.save();
更新数据
最简单的方法,通过find()
找到记录,并使用save()
方法更新记录。
Album albumToUpdate = DataSupport.find(Album.class, 1);
albumToUpdate.setPrice(20.99f); // raise the price
albumToUpdate.save();
每个继承于DataSupport
的模型,都有update()
和updateAll()
方法。
Album albumToUpdate = new Album();
albumToUpdate.setPrice(20.99f); // raise the price
albumToUpdate.update(id);
或者带有where
条件的更新多条记录。
Album albumToUpdate = new Album();
albumToUpdate.setPrice(20.99f); // raise the price
albumToUpdate.updateAll("name = ?", "album");
删除数据
使用DataSupport
中静态方法delete()
删除一条记录。
DataSupport.delete(Song.class, id);
或者使用DataSupport
中静态方法deleteAll()
删除多条记录。
DataSupport.deleteAll(Song.class, "duration > ?" , "350");
查询数据
从【歌曲】表中通过id
查找单一条记录。
Song song = DataSupport.find(Song.class, id);
从【歌曲】表中查找多条记录。
List allSongs = DataSupport.findAll(Song.class);
通过fluent query
构建复杂查询。
List songs = DataSupport.where("name like ?", "song%").order("duration").find(Song.class);
异步操作
默认每个数据库操作都是在主线程上。如果操作可能花费很长的时间,例如保存或者查询大量的记录,可能需要使用异动操作。
LitePal的所有CRUD方法都支持异步操作。例如,在后台线程从【歌曲】表中查找多条记录,代码如下:
DataSupport.findAllAsync(Song.class).listen(new FindMultiCallback() {
@Override
public void onFinish(List t) {
List allSongs = (List) t;
}
});
使用findAllAsync()
代替findAll()
,并且拓展一个listen()
方法,当异步操作完成时,通过回调onFinish()
方法返回查询结果。
相同地,异步存储代码如下:
Album album = new Album();
album.setName("album");
album.setPrice(10.99f);
album.setCover(getCoverImageBytes());
album.saveAsync().listen(new SaveCallback() {
@Override
public void onFinish(boolean success) {
}
});
使用saveAsync()
代替save()
,并且拓展一个listen()
方法,当在后台将【专辑】存储到数据库后,通过回调onFinish()
方法返回存储结果。
多数据库
如果App需要多个数据库,LitePal也是完全支持的。在运行时你可以创建多个想要的数据库。例如:
LitePalDB litePalDB = new LitePalDB("demo2", 1);
litePalDB.addClassName(Singer.class.getName());
litePalDB.addClassName(Album.class.getName());
litePalDB.addClassName(Song.class.getName());
LitePal.use(litePalDB);
上面这段代码是创建一个demo2
的数据库,里面有【歌手】、【专辑】和【歌曲】三张表。
如果你只是想创建一个新的数据库,而不想配置litepal.xml
,你可以参照如下:
LitePalDB litePalDB = LitePalDB.fromDefault("newdb");
LitePal.use(litePalDB);
你可以通过下面的操作切换回默认数据库。
LitePal.useDefault();
你也可以通过表名删除任何数据库。
LitePal.deleteDatabase("newdb");
字符串加密
从1.6.0版本LitePal内置了对数据(字符串)进行AES或者MD5加解密的功能。
AES:全称是Advanced Encryption Standard,中文名叫高级加密标准,同时它也是美国联邦政府采用的一种区块加密标准。
MD5:全称是Message Digest Algorithm 5,中文名叫信息摘要算法第五版。要说到MD5加密算法的特点其实有很多很多,但是它最为突出的一个特点就是,使用这种加密算法计算出来的结果是不可逆的。通俗点来说,就是MD5算法只能进行加密但不能进行解密。
AES
一个书本类,类中有一个【书名】属性和一个【页数】属性,现在将【书名】属性的值进行加密,只需要在【书名】属性的上方加上@Encrypt(algorithm = AES)
这样一行注解即可代码如下:
public class Book extends DataSupport {
@Encrypt(algorithm = AES)
private String name;
private int page;
// getter and setter
}
对于开发者而言,加解密操作是完全透明化的。也就是说,作为开发者并不用考虑某个字段有没有被加密,然后要不要进行解密等等,我们只需要仍然使用标准的LitePal API
来查询数据即可。
比如从书本表中查询这条数据,并打印。
Book book = DataSupport.findFirst(Book.class);
String name = book.getName();
int page = book.getPage();
Log.d(TAG, "book name is " + name);
Log.d(TAG, "book page is " + page);
细节
可以自定义AES算法的密钥。如果没有指定密钥,LitePal会使用默认的密钥进行加解密。使用
LitePal.Key()
方法来自定义密钥;AES算法和MD5算法都只对
String
类型的字段有效,如果你尝试给其他类型的字段(比如说int
字段)指定@Encrypt
注解,LitePal并不会执行任何加密操作;-
加密后的数据字段不能再通过
where
语句来进行查询、修改或删除。
也就是说,执行类似于 where("name = ?", "第一行代码") 这样的语句将无法查到任何数据,因为在数据库中存储的真实值已经不是"第一行代码"了。
MD5
与AES类似,加密基本是一模一样的用法,我们只需要将@Encrypt
中指定的加密算法改成MD5即可。
public class User extends DataSupport {
@Encrypt(algorithm = MD5)
private String password;
private String username;
// getter and setter
}
代码混淆
如果你需要使用Proguard,可能需要添加以下代码到项目文件中。
-keep class org.litepal.** {
*;
}
-keep class * extends org.litepal.crud.DataSupport {
*;
}
ProGuard是一个压缩、优化和混淆Java字节码文件的免费的工具,它可以删除无用的类、字段、方法和属性。可以删除没用的注释,最大限度地优化字节码文件。它还可以使用简短的无意义的名称来重命名已经存在的类、字段、方法和属性。常常用于Android开发用于混淆最终的项目,增加项目被反编译的难度。