相信我崇猫,當(dāng)你用上 LitePal 之后,你將再也不想去碰 SQLiteDatabase 了渣刷。
LitePal是一款開源的 Android 數(shù)據(jù)庫框架苦锨,它采用了對象關(guān)系映射(ORM)的模式,并將我們平時(shí)開發(fā)最常用到的一些數(shù)據(jù)庫功能進(jìn)行了封裝药磺,使得不用編寫一行SQL語句就可以完成各種建表和增刪改查的操作告组。LitePal 的項(xiàng)目主頁上也有詳細(xì)的使用文檔,地址是https://github.com/LitePalFramework/LitePal
OK癌佩,如果看不懂木缝,沒關(guān)系,總之它很好用就是了
首先驼卖,新建一個項(xiàng)目 LitePalTest 氨肌,然后開啟 LitePal 之旅,車速有點(diǎn)慢哈酌畜,耐心看下去怎囚。
如果你看過郭霖大神的《第一行代碼》第二版,可能就沒必要看下去了桥胞,因?yàn)閮?nèi)容基本一致恳守。
1. 配置 LitePal
首先,修改項(xiàng)目的 app/build.gradle 文件贩虾,在 dependencies 閉包中申明LitePal庫的引用
compile 'org.litepal.android:core:1.5.1'
開發(fā)者肯定會對框架的更新的催烘,所以下載最新版的話請前往項(xiàng)目主頁查看https://github.com/LitePalFramework/LitePal
接下來需要配置 litepal.xml 文件。右擊 app/src/main 目錄 ——>New——>Directory缎罢,創(chuàng)建一個 assets 目錄
然后在 assets 目錄下新建一個 litepal.xml 文件伊群,接著編輯該文件考杉,如下所示
最后還需要修改一下 AndroidManifest.xml 中的代碼
加上我選中的哪一行,只有加上這個才能讓 LitePal 的所有功能正常運(yùn)行舰始,關(guān)于 application 的作用崇棠,還請看官自行 Google 。
現(xiàn)在 Litepal 的配置工作已經(jīng)做完了丸卷,讓我們開始正式使用它吧枕稀!
2. 創(chuàng)建和升級數(shù)據(jù)庫
先分析一下數(shù)據(jù)表,需要哪些數(shù)據(jù)谜嫉,我們是一個書店應(yīng)用萎坷,呢么它是不是應(yīng)該存儲書的數(shù)據(jù),那么一本書就是一條數(shù)據(jù)沐兰,這條數(shù)據(jù)有書名哆档、書的作者、書的價(jià)格僧鲁、書的頁數(shù)虐呻,還有數(shù)據(jù)的ID這些字段
LitePal 是采取的對象關(guān)系映射(ORM),我們的編程語言是面向?qū)ο蟮哪海褂玫臄?shù)據(jù)庫則是關(guān)系型數(shù)據(jù)庫斟叼,那么將面向?qū)ο蟮恼Z言和面向關(guān)系的數(shù)據(jù)庫之間建立一種映射關(guān)系,這就是對象關(guān)系映射了春寿,所以我們可以用面向?qū)ο蟮乃季S來操作數(shù)據(jù)庫了朗涩。
所以根據(jù)剛才的分析結(jié)果,我們來定義一個 Book 類绑改,一定要繼承 DataSupport 類谢床,代碼如下所示:
package com.example.litepaltest;
import org.litepal.crud.DataSupport;
/**
* Created by jethro on 2017/6/8.
*/
public class Book extends DataSupport{
private int id ;
private String name; //書名
private double price; //價(jià)格
private int pages; //頁數(shù)
private String author; //作者
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
這是一個典型的 Java Bean ,在 Book 類中我們定義了 id厘线、name识腿、price、pages造壮、author 這幾個字段渡讼,并且生成了相對應(yīng)的 getter 和 setter 方法,不會生成請自行谷歌 “ Android studio 生成getter and setter ”
接著我們修改一下 litepal.xml 的代碼耳璧,如下所示
這里使用<mapping>
標(biāo)簽來申明我們要配置的數(shù)據(jù)類成箫,或者說數(shù)據(jù)表,注意這里一定要使用完整的類名旨枯,只寫 Book 可不行哈蹬昌,不管有多少數(shù)據(jù)表(書上是寫的映射模型類,我覺得這個還是準(zhǔn)確點(diǎn)攀隔,后面就叫映射模型類好了)皂贩,都使用同樣的方式配置在<list>
標(biāo)簽下即可栖榨。
OK,這樣所有的工作都完成了明刷,使用任何一次數(shù)據(jù)庫的操作治泥,BookStore.db 數(shù)據(jù)庫都會被創(chuàng)建出來,然后 Book 數(shù)據(jù)表就在這個數(shù)據(jù)庫里了遮精。
如果你想再 Book 表中新添加一個 press(出版社) 列,直接修改 Book 類中的代碼败潦,添加一個
press 變量即可本冲,如下所示:
記得添加對應(yīng)的 get 和 set 方法,與此同時(shí)我們還想添加一張 category(類別) 表劫扒,那么只需要像剛才一樣檬洞,新建一個 Category 類就可以了,代碼如下所示
改完了所有我們想改的動西沟饥,只需要記得將版本號加1就行了添怔,當(dāng)然由于我們剛才又添加了一個模型類 Category,因此也需要將他添加到<list>
標(biāo)簽中贤旷,代碼如下所示:
3. 操作數(shù)據(jù)庫
對于數(shù)據(jù)庫的操作广料,總結(jié)起來就是四個字:增、刪幼驶、改艾杏、查
增:往數(shù)據(jù)庫里增加數(shù)據(jù),或者說添加數(shù)據(jù)
刪:根據(jù)條件來刪除數(shù)據(jù)庫里的數(shù)據(jù)
改:根據(jù)條件來修改數(shù)據(jù)庫里的數(shù)據(jù)
查:根據(jù)條件來查詢數(shù)據(jù)庫里的數(shù)據(jù)盅藻,這是一個比較考驗(yàn)開發(fā)者技術(shù)的操作
接著我們就對這四個操作一一講解
3.1 增
現(xiàn)在我們來往Book表中添加數(shù)據(jù)购桑,我們 MainActivity 現(xiàn)在有四個按鈕,分別是添加數(shù)據(jù)氏淑、修改數(shù)據(jù)勃蜘、刪除數(shù)據(jù)、查詢數(shù)據(jù)假残,先看添加數(shù)據(jù)的代碼缭贡,代碼如下:
這段代碼很簡單也很神奇,首先我們創(chuàng)建了一個 Book 的實(shí)例守问,然后調(diào)用 Book 類中的 set 方法對數(shù)據(jù)進(jìn)行設(shè)置匀归,最后再調(diào)用 book.save() 方法就能對完成數(shù)據(jù)添加操作了。那么這個 save() 是從哪兒來的呢耗帕?當(dāng)然是從 DataSupport類中繼承來的了穆端,DataSupport 類還給我們提供了豐富的增刪改查的方法。現(xiàn)在我們按一下添加數(shù)據(jù)按鈕仿便,再按查詢數(shù)據(jù)就能看到我們剛才添加的數(shù)據(jù)了体啰。查詢按鈕的代碼最后會進(jìn)行講解
3.2 改
學(xué)習(xí)完了如何添加數(shù)據(jù)攒巍,接下來我們看看如何更新數(shù)據(jù),更新數(shù)據(jù)要比添加數(shù)據(jù)要稍微復(fù)雜一點(diǎn)荒勇,因?yàn)樗?API 接口比較多柒莉,這里我們只介紹幾種最常用的更新方式
首先,最簡單的一種更新方式就是對已存儲的對象重新設(shè)值沽翔,然后重新調(diào)用 save() 方法即可兢孝。那么這里我們就要了解一個概念,什么是已存儲的對象仅偎?
對于LitePal來說跨蟹,對象是否已儲存是根據(jù) model.isSaved() 方法的結(jié)果來判斷的,返回 true 表示已儲存橘沥,返回 false 表示未儲存窗轩。那么接下來的問題是,什么情況下會返回 true 座咆,什么情況下會返回 false 呢痢艺?
實(shí)際上只有兩種情況下 isSaved() 方法才會返回 true ,一種情況是已經(jīng)調(diào)用 save() 方法去添加數(shù)據(jù)了介陶,此時(shí) model 會被認(rèn)為是已儲存的對象堤舒。另一種情況是 model 對象是通過查詢得來的對象,由于是從數(shù)據(jù)庫中查到的對象哺呜,因此也會被認(rèn)為是已儲存的對象植酥。
由于查詢數(shù)據(jù)我們還學(xué)到,因此只能先通過第一種情況來進(jìn)行驗(yàn)證弦牡,修改MainActivity中的代碼友驮,如下所示:
這里我們先是添加了一條書的數(shù)據(jù),然后發(fā)現(xiàn)作者其實(shí)是霍金驾锰,不是老王卸留,搞錯了,于是又調(diào)用
setAuthor() 方法設(shè)置了一下作者椭豫,為了表示歉意耻瑟,我們把價(jià)格也降低成了 14.26 元,最后又調(diào)用 save 方法保存了一下赏酥,此時(shí) LitePal 會發(fā)現(xiàn)當(dāng)前的 Book 對象是已儲存的喳整,于是就不會再向數(shù)據(jù)庫去添加一條新的數(shù)據(jù),而是會直接更新當(dāng)前的數(shù)據(jù)裸扶。
此時(shí)我們按一下修改數(shù)據(jù)按鈕框都,再按一下查詢按鈕
可以看到Book表中新增了一本書,但并不是一開始我們設(shè)置的作者老王呵晨,說明我們的更新操作是成功了魏保。但是這樣的更新方式限制性太大了熬尺,接下來我們學(xué)習(xí)另外一種非更加靈巧的更新方式。修改MainActivity的代碼谓罗,如下所示:
可以看到這里我們先是 new 出了一個 Book 對象粱哼,然后直接調(diào)用 setPrice() 方法設(shè)置要更新的價(jià)格,最后調(diào)用 updateAll() 方法去執(zhí)行更新操作檩咱。注意 updateAll() 可以指定一個約束條件揭措,和 sql 的 where 參數(shù)類似(不懂?自己去學(xué)學(xué) SQL 吧)但更加簡潔刻蚯,如果不指定條件的話蜂筹,就表示更新所有數(shù)據(jù),這里我們指定將書名是時(shí)間簡史并且作者是霍金的書價(jià)格更新為9.9÷梗現(xiàn)在重新運(yùn)行一下,點(diǎn)擊修改數(shù)據(jù)按鈕不翩,再點(diǎn)查詢數(shù)據(jù)按鈕兵扬,結(jié)果如圖:
意料之中,《時(shí)間簡史》的價(jià)格成功被更新為了9.9口蝠,怎么樣器钟?是不是很簡單?
3.3 刪
使用 LitePal 刪除數(shù)據(jù)的方式主要有兩種妙蔗,第一種比較簡單,就是直接調(diào)用已儲存對象的 delete() 方法就可以了,對于已儲存對象的概念汁展,我們上一小節(jié)已經(jīng)學(xué)習(xí)過了猎提。也就是說,調(diào)用過
save() 方法的對象寸五,或者是通過LitePal提供的查詢 API 查出來的對象梳凛,都是可以直接使用 delete() 方法來刪除數(shù)據(jù)的。這種方式比較簡單梳杏,只是把第二次 save() 換成了 delete() 方法而已韧拒,我們就不進(jìn)行代碼演示了,下面來看另外一種刪除數(shù)據(jù)的方式十性。
修改 MainActivity 的代碼叛溢,如下所示
就一行代碼,這里調(diào)用了 DataSupport.deleteAll() 方法來刪除數(shù)據(jù)劲适,其中deleteAll()方法的第一個參數(shù)用于指定刪除那張表中的數(shù)據(jù)楷掉,Book.class 就意味著刪除 Book 表中的數(shù)據(jù),后面的參數(shù)用于指定約束條件霞势,應(yīng)該不難理解靖诗。那么這行代碼的意思就是郭怪,刪除 Book 表中的價(jià)格價(jià)格低于20元的書,目前有兩本書刊橘,一本是 16.9 一本是 9.9鄙才,剛好可以看出效果。
現(xiàn)在重新運(yùn)行一下程序促绵,并點(diǎn)擊刪除數(shù)據(jù)按鈕攒庵,然后查詢數(shù)據(jù)按鈕,結(jié)果如圖所示
可以看到并沒有查詢結(jié)果败晴,說明刪除成功了浓冒,另外,deleteAll() 方法如果不指定約束條件尖坤,就以為著你要刪除表中所有的數(shù)據(jù)稳懒,著一點(diǎn)和 updateAll() 方法是比較相似的。
3.4 查
終于又到了最復(fù)雜的查詢數(shù)據(jù)部門了慢味,不過著嘴復(fù)雜也只是相對于過去而言场梆,因?yàn)槭褂?LitePal 來查詢數(shù)據(jù)一點(diǎn)都不復(fù)雜。我一直都認(rèn)為 LitePal在查詢數(shù)據(jù) API 方面的設(shè)計(jì)極為人性化纯路,要是想獲取表中的數(shù)據(jù)如果用 SQLite 的 query() 方法或油,冗長的參數(shù)列表讓人看著頭疼,即使多數(shù)參數(shù)都是用不到的驰唬,也不得不傳入 null 顶岸,如下所示:
Cursor cursor = db.query("Book",null,null,null,null,null,null);
這樣的代碼恐怕是沒人喜歡的,而使用LitePal則會享受到簡化的操作和優(yōu)雅的體驗(yàn)
上面的代碼是查詢 Book 表中的全部數(shù)據(jù)叫编,那么如果使用 LitePal 來查詢的話辖佣,代碼會是怎么樣的?非常簡單搓逾,只需要這樣寫:
List<Book> books = DataSupport.findAll(Book.class);
怎么樣凌简?這樣的代碼是不是就簡單易懂得多了?沒有冗長得參數(shù)恃逻,只需要調(diào)用一下 findAll() 方法雏搂,然后通過 Book.class 參數(shù)指定查詢 Book 表就可以了。findAll() 方法得返回值是一個 Book 類型得 List 集合寇损,然后你就可以輕松得獲取 Book 對象里的數(shù)據(jù)了凸郑。
下面通過一個完整的例子來實(shí)踐一下吧,修改 MainActivity 中的代碼矛市,如下所示:
查詢的那段代碼剛剛已經(jīng)解釋過了芙沥,接下來就是遍歷 List 集合中的 Book 對象,并將其中的書名、作者而昨、價(jià)格數(shù)據(jù)打印出來救氯。因?yàn)閯倓偽覀儎h除了所有的數(shù)據(jù),那么現(xiàn)在點(diǎn)兩下添加數(shù)據(jù)按鈕歌憨,再點(diǎn)查詢數(shù)據(jù)按鈕着憨,結(jié)果如下:
除了 findAll 方法之外,LitePal 還提供了很多其他非常有用的查詢 API务嫡。比如我們想要查詢 Book 表中的第一條數(shù)據(jù)就可以這樣寫:
Book firstBook = DataSupport.findFirst(Book.class);
查詢 Book 表中的最后一條數(shù)據(jù)就可以這樣寫
Book firstBook = DataSupport.findLast(Book.class);
我們還可以通過連綴查詢功能來定制更多的查詢功能甲抖。
- select() 方法用于指定查詢那幾列的數(shù)據(jù),對應(yīng)了 SQL 當(dāng)中的 select 關(guān)鍵字心铃。比如只查 name 和 author 著兩列的數(shù)據(jù)准谚,就可以這樣寫:
List<Book> books = DataSupport.select("name", "author").find(Book.class);
- where() 方法用于指定約束條件,對應(yīng)了 SQL 當(dāng)中的 where 關(guān)鍵字去扣。比如只查價(jià)格低于 10 塊錢的書柱衔,就可以這么寫:
List<Book> books = DataSupport.where("price < ?", "10").find(Book.class);
- order() 方法用于指定結(jié)果的排序方式,對應(yīng)了 SQL 當(dāng)中的 order by 關(guān)鍵字愉棱。比如將查詢結(jié)果按照書價(jià)從高到低排序唆铐,就可以這樣寫:
List<Book> books = DataSupport.order("price desc").find(Book.class);
//其中 desc 表示降序排列,asc 或者不屑表示升序排列羽氮。
- limit() 方法用于指定查詢結(jié)果的數(shù)量,比如只查詢表中的前 3 條數(shù)據(jù)惫恼,就可以這么寫:
List<Book> books = DataSupport.limit(3).find(Book.class);
- offset() 方法用于指定查詢結(jié)果的偏移量档押,比如查詢表中的第 2 ~ 4 條數(shù)據(jù),就可以這么寫:
List<Book> books = DataSupport.limit(3).offset(1).find(Book.class);
當(dāng)然祈纯,你還可以對這5個方法進(jìn)行任意的連綴組合令宿,來完成一個比較復(fù)雜的查詢操作:
List<Book> books = DataSupport.select("name", "author", "price")
.where("price < ?", "10")
.order("price")
.limit(10)
.offset(10)
.find(Book.class);
這段代碼就表示,查詢 Book 表中的第 11 ~ 20 條滿足與價(jià)格小于 10 塊錢的條件的數(shù)據(jù)腕窥,并且只要 name粒没、author、price 這三列數(shù)據(jù)簇爆。并將查詢結(jié)果按照價(jià)格升序排列癞松。
怎么樣?是不是感覺 LitePal 的查詢功能非常強(qiáng)大入蛆?并且代碼簡潔响蓉,邏輯清晰?關(guān)于 LitePal 的查詢 API 就講到這里了哨毁,這些 API 已經(jīng)足夠我們應(yīng)用絕大多數(shù)廠場景的查詢需求了枫甲。當(dāng)然如果你實(shí)在有一些特殊的需求,上述的 API 已經(jīng)滿足不了你的時(shí)候,LitePal 任然支持原生的 SQL 來進(jìn)行查詢:
Cursor c = DataSupport.findBySQL("select * from Book where pages > ? and price < ?", "400", "20");
這里的 Cursor 對象里的數(shù)據(jù)如何取出還請百度之想幻。
4. 結(jié)束語
非常感謝看官能看到這里,相信你已經(jīng)能完成一些簡單的數(shù)據(jù)儲存了吧脏毯?如果對于條件約束這些不理解,還是建議去自學(xué)一下 SQL