本文目的在于,針對(duì)room原生api中有一些不方便的地方,基于注解與RxJava孙援,kotlin的強(qiáng)大lambda表達(dá)式進(jìn)行包裝節(jié)省大量開(kāi)發(fā)工作害淤。
谷歌發(fā)布了ROOM數(shù)據(jù)庫(kù),與其他常見(jiàn)數(shù)據(jù)庫(kù)api的區(qū)別是拓售,基于注解與sql窥摄,不需要像其他庫(kù)一樣去記數(shù)據(jù)庫(kù)內(nèi)置的DAO的各種操作api函數(shù),數(shù)據(jù)庫(kù)遷移功能很強(qiáng)大而且邏輯清晰础淤,便于維護(hù)崭放。官方支持RxJava,對(duì)于查詢(xún)結(jié)果可以很方便的實(shí)現(xiàn)異步訂閱鸽凶。
Room提供給我們的是一個(gè)基礎(chǔ)的有無(wú)限可能的庫(kù)莹菱,也許對(duì)于新手程序員來(lái)說(shuō),不如greendao等庫(kù)用起來(lái)足夠傻瓜式(只需要記住增刪改查的api吱瘩,不需要自己去寫(xiě)dao的sql語(yǔ)句)道伟,但是谷歌的庫(kù)都有一個(gè)特點(diǎn),就是基于你的能力使碾,可以有無(wú)限的擴(kuò)展可能(databinding庫(kù)也是類(lèi)似蜜徽,新手覺(jué)得沒(méi)有便捷多少,但是如果你自己積累票摇,編寫(xiě)了很多自定義xml屬性拘鞋,和自己改造包裝通用的工具方法,databinding甚至可以讓給你在xml中一行屬性完成listView的adapter從創(chuàng)建矢门,填充數(shù)據(jù)一條龍服務(wù)盆色,這點(diǎn)稍后會(huì)把我的基于databinding的包裝心得寫(xiě)一篇文章,拋磚引玉祟剔,啟發(fā)大家想出天馬行空的使用方式)隔躲。關(guān)于數(shù)據(jù)庫(kù)的使用不做過(guò)于詳細(xì)的講解,我這里只對(duì)于從0開(kāi)始組建room數(shù)據(jù)庫(kù)實(shí)踐過(guò)程中的心得物延,如何利用宣旱。
關(guān)于ROOM的痛點(diǎn):
1.對(duì)比與其他的開(kāi)源數(shù)據(jù)庫(kù),在創(chuàng)建dao的時(shí)候叛薯,需要手動(dòng)寫(xiě)增刪該查浑吟,如果表很多,也有不小的工作量耗溜。
2.不進(jìn)行包裝组力,原生使用方式基于Dao對(duì)象操作,對(duì)于增刪改查都要寫(xiě)大量的rxJava的訂閱監(jiān)聽(tīng)以及線程的模版代碼抖拴,這些都可以通過(guò)技術(shù)手段簡(jiǎn)化燎字,避免。
github地址:
一.下面我們來(lái)看一下原生的Room使用過(guò)程(歸結(jié)為:Entity,Dao家夺,DataBase三大對(duì)象):
1.對(duì)數(shù)據(jù)對(duì)象進(jìn)行@entity注解處理脱柱,轉(zhuǎn)化為Entity類(lèi):比較簡(jiǎn)單,class上標(biāo)記@Entity拉馋,對(duì)于主鍵變量榨为,標(biāo)記@PrimaryKey
2.根據(jù)Entity對(duì)象,創(chuàng)建對(duì)應(yīng)對(duì)DAO類(lèi)煌茴,通過(guò)注解的方式随闺,將SQL(不用害怕敲sql,用room庫(kù)的話蔓腐,在敲sql的時(shí)候也是有代碼提示的矩乐,不會(huì)像寫(xiě)純string一樣出現(xiàn)筆誤等情況。)語(yǔ)句注冊(cè)給對(duì)應(yīng)對(duì)操作方法:
3. 創(chuàng)建自己的DataBase類(lèi)(繼承RoomDatabase)回论,聲明你之前創(chuàng)建的dao的操作方法
4.以查詢(xún)方法為例子散罕,api的實(shí)際調(diào)用:獲取數(shù)據(jù)庫(kù)實(shí)例,獲取dao實(shí)例傀蓉,操作dao的方法欧漱。
二.本文的包裝思路與實(shí)際操作預(yù)覽:
下面是我的包裝方法:首先解決不必要重復(fù)寫(xiě)的增刪等方法。然后已一個(gè)DataBaseHelper類(lèi)來(lái)包裝葬燎,操作數(shù)據(jù)庫(kù)误甚,將rxjava的訂閱過(guò)程包裝起來(lái),并且引入帶參數(shù)的查詢(xún)谱净。
主要解決問(wèn)題就是免去大量的模版代碼窑邦,rxjava代碼,線程操作壕探,數(shù)據(jù)庫(kù)操作奕翔,都由
最終預(yù)覽下,我們想調(diào)用一個(gè)SearchRecordDao來(lái)查詢(xún)浩蓉,獲取到一個(gè)結(jié)果list派继,顯示到一個(gè)textview上,最終的全部代碼如下:
一行代碼完成查詢(xún)過(guò)程捻艳,不用關(guān)心數(shù)據(jù)庫(kù)如何創(chuàng)建驾窟,dao如何創(chuàng)建,異步線程操作等等都不需要在開(kāi)發(fā)時(shí)候重復(fù)去操作了认轨。
三.大致結(jié)構(gòu)與流程:
結(jié)構(gòu):
流程:
四. 主要代碼講解:
1.Dao類(lèi)注解的標(biāo)記:
其中@IsQuery :無(wú)參數(shù)查詢(xún)所有數(shù)據(jù)绅络;@IsQueryWithKey 帶一個(gè)參數(shù)的查詢(xún),@IsDeleteAll :刪除全部。 以上這些方法的Sql其實(shí)都可以copy恩急,只是表名不同杉畜。
2.DBHelper 中的工作:
當(dāng)這個(gè)Dao被創(chuàng)建標(biāo)記完成以后,我們馬上就可以通過(guò)操作 DBHelper來(lái)進(jìn)行操作這個(gè)表的查詢(xún)衷恭,比如要調(diào)用通過(guò) id查詢(xún)結(jié)果(getSearchRecordById()方法):傳一個(gè)key此叠,Dao的class,成功獲取結(jié)果后的回調(diào)函數(shù)(lambda表達(dá)式)
這個(gè)調(diào)用對(duì)應(yīng)都就是我們剛才在SearchRecordDao.class里的getResearchRecordById()方法随珠,它是通過(guò)注解 @ IsQueryWithKey被識(shí)別灭袁,當(dāng)我們調(diào)用時(shí)候傳的“1270030”就是id參數(shù)。
首先窗看,通過(guò)DBHelper找到dao茸歧,然后調(diào)用dao的對(duì)應(yīng)帶參數(shù)查詢(xún)方法,數(shù)據(jù)庫(kù)的關(guān)閉也在這里進(jìn)行显沈。queryListWithKey方法如下:
其中的success 和fail 類(lèi)型為 (t:List)->(Unit)這個(gè)代表一個(gè)lambda表達(dá)式软瞎,
對(duì)于lambda不熟悉的同學(xué),我簡(jiǎn)答講解下怎么理解這個(gè)東西拉讯。
當(dāng)這個(gè)表達(dá)式success(t)被調(diào)用的時(shí)候铜涉,這個(gè)方法的設(shè)計(jì)者會(huì)把他查詢(xún)到的結(jié)果(一個(gè)list<T>)通過(guò)invoke這個(gè)表達(dá)式的方式傳遞給你,以便于你的表達(dá)式在編寫(xiě)的時(shí)候遂唧,就可以針對(duì)這個(gè)查詢(xún)結(jié)果出來(lái)以后芙代,如何進(jìn)行下一步工作給出方案。其中suceess(t) 就是調(diào)用lambda表達(dá)式盖彭,其實(shí)它和調(diào)用函數(shù)是一樣的纹烹。如果熟悉c,c++的同學(xué)召边,可以發(fā)現(xiàn)铺呵,它和函數(shù)指針的概念很像。
對(duì)于用java的同學(xué)隧熙,可以這樣對(duì)照l(shuí)ambda和匿名內(nèi)部類(lèi):
{? list-> int size = list.size() }? 可以這樣理解 片挂,假設(shè)又一個(gè)Success接口包含一個(gè)參數(shù)為list的方法扮惦,
success = new Success(){??
@override
public void recall(List<T> list){
int size = list.size();
} }
其實(shí)任何一個(gè)lambda表達(dá)式铅檩,都可以用一個(gè)接口來(lái)代替耘子。而相對(duì)于接口姨丈,lambda可以說(shuō),是去掉了定義接口類(lèi)扫腺,創(chuàng)建匿名對(duì)象這一過(guò)程砌创,可以用一個(gè)式子來(lái)完成全部工作姆打。
3.Dao中的代碼:
dao中的具體實(shí)現(xiàn)方法件余,都在BaseDao中讥脐,由父類(lèi)實(shí)現(xiàn)了 insert遭居,delete ,update等方法旬渠。子類(lèi)中主要就是聲明query方法俱萍,并用注解中寫(xiě)好Sql語(yǔ)句。
BaseDao:
這個(gè)方法雖然是在BaseDao中告丢,但我們但子類(lèi)Dao中會(huì)繼承這個(gè)方法枪蘑,當(dāng)它在運(yùn)行時(shí)候,反射獲取的所有method是當(dāng)前子類(lèi)的所有方法芋齿,這樣我們?cè)趯?xiě)B(tài)aseDao的時(shí)候,就可以實(shí)現(xiàn)找到將來(lái)任意一個(gè)子類(lèi)中代表了有參查詢(xún)@IsQueryWithKey的方法,并且調(diào)用這個(gè)方法成翩,在父類(lèi)里就預(yù)先寫(xiě)好RxJava的訂閱觅捆。