【Android】LitePal安装和使用

【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:ORMAndroidLitePal

[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文件,并编辑修改为以下代码:

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <!--
        Define the database name of your application. 
        By default each database name should be end with .db. 
        If you didn't name your database end with .db, 
        LitePal would plus the suffix automatically for you.
        For example:    
        <dbname value="demo" />
    -->
    <dbname value="demo" />

    <!--
        Define the version of your database. Each time you want 
        to upgrade your database, the version tag would helps.
        Modify the models you defined in the mapping tag, and just 
        make the version value plus one, the upgrade of database
        will be processed automatically without concern.
            For example:    
        <version value="1" />
    -->
    <version value="1" />

    <!--
        Define your models in the list with mapping tag, LitePal will
        create tables for each mapping class. The supported fields
        defined in models will be mapped into columns.
        For example:    
        <list>
            <mapping class="com.test.model.Reader" />
            <mapping class="com.test.model.Magazine" />
        </list>
    -->
    <list>
    </list>
    
    <!--
        Define where the .db file should be. "internal" means the .db file
        will be stored in the database folder of internal storage which no
        one can access. "external" means the .db file will be stored in the
        path to the directory on the primary external storage device where
        the application can place persistent files it owns which everyone
        can access. "internal" will act as default.
        For example:
        <storage value="external" />
        <storage value="wolf/database" />
    -->
    
</litepal>

将加密数据库存储在SD卡

如果需要将加密后的数据库保存到SD卡上,则需要修改litepal.xml中的配置。代码如下:

<litepal>
    
    <storage value="wolf/database" />

</litepal>

注意:不需要填写SD卡的完成路径,需要配置相对路径即可。

由于LitePal中既没有Activity也没有Fragment,所以LitePal是不会去帮你申请运行时的SD卡访问读写权限。如果选择将数据库文件存储在SD卡上,请一定要确保你的应用程序已经对访问SD卡权限进行了运行时权限处理,否则LitePal的所有操作都将会失败。

配置LitePalApplication

配置AndroidManifest.xml如下:

<manifest>
    <application
        android:name="org.litepal.LitePalApplication">

    </application>
</manifest>

当然,还有一种配置方法。

<manifest>
    <application
        android:name="com.example.MyOwnApplication">
    </application>
</manifest>
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<Song> songs = new ArrayList<Song>();

    // 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文件中添加这两个模型的映射列表。

<list>
    <mapping class="org.litepal.litepalsample.model.Album" />
    <mapping class="org.litepal.litepalsample.model.Song" />
</list>

这样,当进行数据库操作的时候,会自动生成表。例如:

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<Song> songs = new ArrayList<Song>();

    // generated getters and setters.
    
}

litepal.xml文件中的数据库版本会自动进行更新。

<!--
    Define the version of your database. Each time you want 
    to upgrade your database, the version tag would helps.
    Modify the models you defined in the mapping tag, and just 
    make the version value plus one, the upgrade of database
    will be processed automatically without concern.
    For example:    
    <version value="1" ></version>
-->
<version value="2" ></version>

保存数据

保存操作的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<Song> allSongs = DataSupport.findAll(Song.class);

通过fluent query构建复杂查询。

List<Song> songs = DataSupport.where("name like ?", "song%").order("duration").find(Song.class);

异步操作

默认每个数据库操作都是在主线程上。如果操作可能花费很长的时间,例如保存或者查询大量的记录,可能需要使用异动操作。

LitePal的所有CRUD方法都支持异步操作。例如,在后台线程从【歌曲】表中查找多条记录,代码如下:

DataSupport.findAllAsync(Song.class).listen(new FindMultiCallback() {
    @Override
    public <T> void onFinish(List<T> t) {
        List<Song> allSongs = (List<Song>) 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开发用于混淆最终的项目,增加项目被反编译的难度。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,469评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 睡前给李吵吵敷面膜涂乳液,我说我把你弄得白白嫩嫩的,万一你被人抢走了怎么办? “祝福我啊!”李吵吵毫不犹豫回复。
    无非是青梅遇见西柚阅读 163评论 0 0
  • 《亲子日记》第四天 3月22日 星期四 多云 今天宝贝们都表现的很好,小宝去上学高高兴兴的,下午回...
    程文颖阅读 189评论 0 0
  • 变量,是容器里的内容可变,常量不能变,变量可以随时释放,常量必须在脚本结束才能释放,人为是不能释放的。在项目中,有...
    43e03964ffe2阅读 571评论 0 0