【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开发用于混淆最终的项目,增加项目被反编译的难度。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

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