【Android】LitePal安裝和使用

【Android】LitePal安裝和使用

本文基本上為整理稿。感謝LitePal的作者和郭霖大神。

參考文獻:

Github — https://github.com/LitePalFramework/LitePal

《LitePal 1.6.0版本來襲,數(shù)據(jù)加解密功能保障你的應(yīng)用數(shù)據(jù)安全》— https://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA%3D%3D&mid=2650240766&idx=1&sn=096f029aa531d5d99191c3d4c9126fc1#wechat_redirect

Tag:ORM,Android、LitePal

[TOC]

關(guān)于LitePal

LitePal是一個可以讓開發(fā)者更簡單操作SQLite的開源Android庫。你不用寫SQL命令就可以完成大部分諸如創(chuàng)建或更新表、CRUD操作和聚合函數(shù)等數(shù)據(jù)庫操作。LitePal的安裝也十分簡單,不用5分鐘就可以集成到你的項目中。

特性

  • 使用對象關(guān)系映射(ORM)設(shè)計模式;
  • 幾乎零配置(僅僅配置一個很少屬性的配置文件);
  • 自動維護所有的表(比如:創(chuàng)建表、修改表和刪除表);
  • 多數(shù)據(jù)庫支持;
  • 為避免寫SQL語句而封裝了APIs;
  • 極為流暢的查詢API;
  • 仍然還可以選擇使用SQL,但APIs要比原生的更好更容易。

安裝

導入庫

在AndroidStudio中,編輯build.gradle文件,加入以下:

dependencies {
    compile 'org.litepal.android:core:1.6.0'
}

配置litepal.xml

在項目中的assets文件下,創(chuàng)建并命名一個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>

將加密數(shù)據(jù)庫存儲在SD卡

如果需要將加密后的數(shù)據(jù)庫保存到SD卡上,則需要修改litepal.xml中的配置。代碼如下:

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

</litepal>

注意:不需要填寫SD卡的完成路徑,需要配置相對路徑即可。

由于LitePal中既沒有Activity也沒有Fragment,所以LitePal是不會去幫你申請運行時的SD卡訪問讀寫權(quán)限。如果選擇將數(shù)據(jù)庫文件存儲在SD卡上,請一定要確保你的應(yīng)用程序已經(jīng)對訪問SD卡權(quán)限進行了運行時權(quán)限處理,否則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)。

使用

創(chuàng)建表

比如,有兩個模型類:【專輯】和【歌曲】。定義模型如下:

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>

這樣,當進行數(shù)據(jù)庫操作的時候,會自動生成表。例如:

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
);

更新表

例如添加一個發(fā)布時間字段并注釋掉【售價】字段:

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文件中的數(shù)據(jù)庫版本會自動進行更新。

<!--
    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>

保存數(shù)據(jù)

保存操作的API是面向?qū)ο蟮?。每個繼承于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();

更新數(shù)據(jù)

最簡單的方法,通過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");

刪除數(shù)據(jù)

使用DataSupport中靜態(tài)方法delete()刪除一條記錄。

DataSupport.delete(Song.class, id);

或者使用DataSupport中靜態(tài)方法deleteAll()刪除多條記錄。

DataSupport.deleteAll(Song.class, "duration > ?" , "350");

查詢數(shù)據(jù)

從【歌曲】表中通過id查找單一條記錄。

Song song = DataSupport.find(Song.class, id);

從【歌曲】表中查找多條記錄。

List<Song> allSongs = DataSupport.findAll(Song.class);

通過fluent query構(gòu)建復雜查詢。

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

異步操作

默認每個數(shù)據(jù)庫操作都是在主線程上。如果操作可能花費很長的時間,例如保存或者查詢大量的記錄,可能需要使用異動操作。

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()方法,當異步操作完成時,通過回調(diào)onFinish()方法返回查詢結(jié)果。

相同地,異步存儲代碼如下:

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()方法,當在后臺將【專輯】存儲到數(shù)據(jù)庫后,通過回調(diào)onFinish()方法返回存儲結(jié)果。

多數(shù)據(jù)庫

如果App需要多個數(shù)據(jù)庫,LitePal也是完全支持的。在運行時你可以創(chuàng)建多個想要的數(shù)據(jù)庫。例如:

LitePalDB litePalDB = new LitePalDB("demo2", 1);
litePalDB.addClassName(Singer.class.getName());
litePalDB.addClassName(Album.class.getName());
litePalDB.addClassName(Song.class.getName());
LitePal.use(litePalDB);

上面這段代碼是創(chuàng)建一個demo2的數(shù)據(jù)庫,里面有【歌手】、【專輯】和【歌曲】三張表。

如果你只是想創(chuàng)建一個新的數(shù)據(jù)庫,而不想配置litepal.xml,你可以參照如下:

LitePalDB litePalDB = LitePalDB.fromDefault("newdb");
LitePal.use(litePalDB);

你可以通過下面的操作切換回默認數(shù)據(jù)庫。

LitePal.useDefault();

你也可以通過表名刪除任何數(shù)據(jù)庫。

LitePal.deleteDatabase("newdb");

字符串加密

從1.6.0版本LitePal內(nèi)置了對數(shù)據(jù)(字符串)進行AES或者MD5加解密的功能。

AES:全稱是Advanced Encryption Standard,中文名叫高級加密標準,同時它也是美國聯(lián)邦政府采用的一種區(qū)塊加密標準。

MD5:全稱是Message Digest Algorithm 5,中文名叫信息摘要算法第五版。要說到MD5加密算法的特點其實有很多很多,但是它最為突出的一個特點就是,使用這種加密算法計算出來的結(jié)果是不可逆的。通俗點來說,就是MD5算法只能進行加密但不能進行解密。

AES

一個書本類,類中有一個【書名】屬性和一個【頁數(shù)】屬性,現(xiàn)在將【書名】屬性的值進行加密,只需要在【書名】屬性的上方加上@Encrypt(algorithm = AES)這樣一行注解即可代碼如下:

public class Book extends DataSupport {
    @Encrypt(algorithm = AES)
    private String name;
    private int page;
    
    // getter and setter
}

對于開發(fā)者而言,加解密操作是完全透明化的。也就是說,作為開發(fā)者并不用考慮某個字段有沒有被加密,然后要不要進行解密等等,我們只需要仍然使用標準的LitePal API來查詢數(shù)據(jù)即可。

比如從書本表中查詢這條數(shù)據(jù),并打印。

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);

細節(jié)

  • 可以自定義AES算法的密鑰。如果沒有指定密鑰,LitePal會使用默認的密鑰進行加解密。使用LitePal.Key()方法來自定義密鑰;

  • AES算法和MD5算法都只對String類型的字段有效,如果你嘗試給其他類型的字段(比如說int字段)指定@Encrypt注解,LitePal并不會執(zhí)行任何加密操作;

  • 加密后的數(shù)據(jù)字段不能再通過where語句來進行查詢、修改或刪除。

    ?

    也就是說,執(zhí)行類似于 where("name = ?", "第一行代碼") 這樣的語句將無法查到任何數(shù)據(jù),因為在數(shù)據(jù)庫中存儲的真實值已經(jīng)不是"第一行代碼"了。

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是一個壓縮、優(yōu)化和混淆Java字節(jié)碼文件的免費的工具,它可以刪除無用的類、字段、方法和屬性??梢詣h除沒用的注釋,最大限度地優(yōu)化字節(jié)碼文件。它還可以使用簡短的無意義的名稱來重命名已經(jīng)存在的類、字段、方法和屬性。常常用于Android開發(fā)用于混淆最終的項目,增加項目被反編譯的難度。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,034評論 25 709
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • 睡前給李吵吵敷面膜涂乳液,我說我把你弄得白白嫩嫩的,萬一你被人搶走了怎么辦? “祝福我啊!”李吵吵毫不猶豫回復。
    無非是青梅遇見西柚閱讀 217評論 0 0
  • 《親子日記》第四天 3月22日 星期四 多云 今天寶貝們都表現(xiàn)的很好,小寶去上學高高興興的,下午回...
    程文穎閱讀 211評論 0 0
  • 變量,是容器里的內(nèi)容可變,常量不能變,變量可以隨時釋放,常量必須在腳本結(jié)束才能釋放,人為是不能釋放的。在項目中,有...
    43e03964ffe2閱讀 654評論 0 0

友情鏈接更多精彩內(nèi)容