久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Android數(shù)據(jù)庫高手秘籍(十)

 quasiceo 2018-10-13

Android數(shù)據(jù)庫高手秘籍(十)——如何在Kotlin中更好地使用LitePal

2018年10月12日 07:07:03 guolin 閱讀數(shù):1332 標(biāo)簽: Android LitePal Kotlin 數(shù)據(jù)庫 泛型 更多
個(gè)人分類: Android疑難解析
版權(quán)聲明:本文出自郭霖的博客,轉(zhuǎn)載必須注明出處,。 https://blog.csdn.net/sinyu890807/article/details/82714414

轉(zhuǎn)載請(qǐng)注明出處:https://blog.csdn.net/guolin_blog/article/details/82714414

本文同步發(fā)表于我的微信公眾號(hào),掃一掃文章底部的二維碼或在微信搜索 郭霖 即可關(guān)注,,每個(gè)工作日都有文章更新,。

自從LitePal在2.0.0版本中全面支持了Kotlin之后,我也一直在思考如何讓LitePal更好地融入和適配Kotlin語言,,而不僅僅停留在簡(jiǎn)單的支持層面,。

Kotlin確實(shí)是一門非常出色的語言,里面有許多優(yōu)秀的特性是在Java中無法實(shí)現(xiàn)的,。因此,,在LitePal全面支持了Kotlin之后,我覺得如果我還視這些優(yōu)秀特性而不見的話,,就有些太暴殄天物了,。所以在最新的LitePal 3.0.0版本里面,我準(zhǔn)備讓LitePal更加充分地利用Kotlin的一些語言特性,,從而讓我們的開發(fā)更加輕松,。

本篇文章除了介紹LitePal 3.0.0版本的升級(jí)內(nèi)容之外,還會(huì)講解一些Kotlin方面的高級(jí)知識(shí),。

升級(jí)到3.0.0

首先還是來看如何升級(jí)。

為什么這次的版本號(hào)跨度如此之大,直接從2.0升到了3.0呢,?因?yàn)檫@次LitePal在結(jié)構(gòu)上面有了一個(gè)質(zhì)的變化,。

為了更好地兼容Kotlin語言,LitePal現(xiàn)在不再只是一個(gè)庫了,,而是變成了兩個(gè)庫,,根據(jù)你使用的語言不同,需要引入的庫也不同,。如果你使用的是Java,,那么就在build.gradle中引入如下配置:

dependencies {
    implementation 'org.litepal.android:java:3.0.0'
}
  • 1
  • 2
  • 3

而如果你使用的是Kotlin,那么就在build.gradle中引入如下配置:

dependencies {
    implementation 'org.litepal.android:kotlin:3.0.0'
}
  • 1
  • 2
  • 3

好了,,接下來我們就一起看一看LitePal 3.0.0版本到底變更了哪些東西,。

泛型的優(yōu)化

不得不說,其實(shí)LitePal的泛型設(shè)計(jì)一直都不是很友好,,尤其在異步查詢的時(shí)候格外難受,,比如我們看下如下代碼:

在異步查詢的onFinish()回調(diào)中,我們直接得到的并不是查詢的對(duì)象,,而是一個(gè)泛型T對(duì)象,,還需要再經(jīng)過一次強(qiáng)制轉(zhuǎn)型才能得到真正想要查詢的對(duì)象。

如果你覺得這還不算難受的話,,那么再來看看下面這個(gè)例子:

可以看到,,這次查詢返回的是一個(gè)List<T>,我們必須要對(duì)整個(gè)List進(jìn)行強(qiáng)制轉(zhuǎn)型,。不僅要多寫一行代碼,,關(guān)鍵是開發(fā)工具還會(huì)給出一個(gè)很丑的警告。

這樣的設(shè)計(jì)無論如何都算不上友好,。

這里非常感謝 xiazunyang 這位朋友在GitHub上提出的這個(gè)Issue(https://github.com/LitePalFramework/LitePal/issues/396),,并且給出了建議的優(yōu)化方案,LitePal 3.0.0版本在泛型方面的優(yōu)化很大程度上是基于他的建議,。

那么我們現(xiàn)在來看看,,到了LitePal 3.0.0版本,同樣的功能可以怎么寫:

LitePal.findAsync(Song.class, 1).listen(new FindCallback<Song>() {
    @Override
    public void onFinish(Song song) {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看到,,這里在FindCallback接口上聲明了泛型類型為Song,,那么在onFinish()方法回調(diào)中的參數(shù)就可以直接指定為Song類型了,從而避免了一次強(qiáng)制類型轉(zhuǎn)換,。

那么同樣地,,在查詢多條數(shù)據(jù)的時(shí)候就可以這樣寫:

LitePal.where("duration > ?", "100").findAsync(Song.class).listen(new FindMultiCallback<Song>() {
    @Override
    public void onFinish(List<Song> list) {

    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

這次就清爽多了吧,在onFinish()回調(diào)方法中,,我們直接拿到的就是一個(gè)List<Song>集合,,而不會(huì)再出現(xiàn)那個(gè)丑丑的警告了,。

而如果這段代碼使用Kotlin來編寫的話,將會(huì)更加的精簡(jiǎn):

LitePal.where("duration > ?", "100").findAsync(Song::class.java).listen { list ->
    
}
  • 1
  • 2
  • 3

得益于Kotlin出色的lambda機(jī)制,,我們的代碼可以得到進(jìn)一步精簡(jiǎn),。在上述代碼中,行尾的list參數(shù)就是查詢出來的List<Song>集合了,。

那么關(guān)于泛型優(yōu)化的講解就到這里,,下面我們來看另一個(gè)主題,監(jiān)聽數(shù)據(jù)庫的創(chuàng)建和升級(jí),。

監(jiān)聽數(shù)據(jù)庫的創(chuàng)建和升級(jí)

沒錯(cuò),,LitePal 3.0.0版本新增了監(jiān)聽數(shù)據(jù)庫的創(chuàng)建和升級(jí)功能。

加入這個(gè)功能是因?yàn)?JakeHao 這位朋友在GitHub上提了一個(gè)Issue(https://github.com/LitePalFramework/LitePal/issues/414),,在他說明了應(yīng)用場(chǎng)景之后,,我認(rèn)為監(jiān)聽數(shù)據(jù)庫創(chuàng)建和升級(jí)這個(gè)功能還是非常有意義的。

)

要實(shí)現(xiàn)這個(gè)功能肯定要添加新的接口了,,而我對(duì)于添加新接口保持著一種比較謹(jǐn)慎的態(tài)度,,因?yàn)橐紤]到接口的易用性和對(duì)整體框架的影響。

LitePal的每一個(gè)接口我都要盡量將它設(shè)計(jì)得簡(jiǎn)單好用,,因此大家應(yīng)該也可以猜到了,,監(jiān)聽數(shù)據(jù)庫創(chuàng)建和升級(jí)這個(gè)功能會(huì)非常容易,只需要簡(jiǎn)單幾行代碼就可以了實(shí)現(xiàn)了:

LitePal.registerDatabaseListener(new DatabaseListener() {
    @Override
    public void onCreate() {
    }

    @Override
    public void onUpgrade(int oldVersion, int newVersion) {
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

需要注意的是,,registerDatabaseListener()方法一定要確保在任何其他數(shù)據(jù)庫操作之前調(diào)用,,然后當(dāng)數(shù)據(jù)庫創(chuàng)建的時(shí)候,onCreate()方法就會(huì)得到回調(diào),,當(dāng)數(shù)據(jù)庫升級(jí)的時(shí)候onUpgrade()方法就會(huì)得到回調(diào),,并且告訴通過參數(shù)告訴你之前的老版本號(hào),以及升級(jí)之后的新版本號(hào),。

Kotlin版的代碼也是類似的,,但是由于這個(gè)接口有兩個(gè)回調(diào)方法,因此用不了Kotlin的單抽象方法(SAM)這種語法糖,,只能使用實(shí)現(xiàn)接口的匿名對(duì)象這種寫法:

LitePal.registerDatabaseListener(object : DatabaseListener {
    override fun onCreate() {
    }

    override fun onUpgrade(oldVersion: Int, newVersion: Int) {
    }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

這樣我們就將監(jiān)聽數(shù)據(jù)庫創(chuàng)建和升級(jí)這部分內(nèi)容也快速介紹完了,,接下來即將進(jìn)入到本篇文章的重頭戲內(nèi)容。

一次不可思議的升級(jí)

從上述文章中我們都可以看出,,Kotlin版的代碼普遍都是比Java代碼要更簡(jiǎn)約的,,Google給出的官方統(tǒng)計(jì)是,使用Kotlin開發(fā)可以減少大約25%以上的代碼,。

但是處處講究簡(jiǎn)約的Kotlin,,卻在有一處用法上讓我著實(shí)很難受。比如使用Java查詢song表中id為1的這條記錄是這樣寫的:

Song song = LitePal.find(Song.class, 1);
  • 1

而同樣的功能在Kotlin中卻需要這樣寫:

val song = LitePal.find(Song::class.java, 1)
  • 1

由于LitePal必須知道要查詢哪個(gè)表當(dāng)中的數(shù)據(jù),,因此一定要傳遞一個(gè)Class參數(shù)給LitePal才行,。在Java中我們只需要傳入Song.class即可,,但是在Kotlin中的寫法卻變成了Song::class.java,反而比Java代碼更長(zhǎng)了,,有沒有覺得很難受,?

當(dāng)然,,很多人寫著寫著也就習(xí)慣了,,這并不是什么大問題。但是隨著我深入學(xué)習(xí)Kotlin之后,,我發(fā)現(xiàn)Kotlin提供了一個(gè)相當(dāng)強(qiáng)大的機(jī)制可以優(yōu)化這個(gè)問題,,這個(gè)機(jī)制叫作泛型實(shí)化。接下來我會(huì)對(duì)泛型實(shí)化的概念和用法做個(gè)詳細(xì)的講解,。

要理解泛型實(shí)化,,首先你需要知道泛型擦除的概念。

不管是Java還是Kotlin,,只要是基于JVM的語言,,泛型基本都是通過類型擦除來實(shí)現(xiàn)的。也就是說泛型對(duì)于類型的約束只在編譯時(shí)期存在,,運(yùn)行時(shí)期是無法直接對(duì)泛型的類型進(jìn)行檢查的,。例如,我們創(chuàng)建一個(gè)List<String>集合,,雖然在編譯時(shí)期只能向集合中添加字符串類型的元素,,但是在運(yùn)行時(shí)期JVM卻并不能知道它本來只打算包含哪種類型的元素,只能識(shí)別出來它是個(gè)List,。

Java的泛型擦除機(jī)制,,使得我們不可能使用if (a instanceof T),或者是T.class這樣的語法,。

而Kotlin也是基于JVM的語言,,因此Kotlin的泛型在運(yùn)行時(shí)也是會(huì)被擦除的。但是Kotlin中提供了一個(gè)內(nèi)聯(lián)函數(shù)的概念,,內(nèi)聯(lián)函數(shù)中的代碼會(huì)在編譯的時(shí)候自動(dòng)被替換到調(diào)用它的地方,,這就使得原有方法調(diào)用時(shí)的形參聲明和實(shí)參傳遞,在編譯之后直接變成了同一個(gè)方法內(nèi)的變量調(diào)用,。這樣的話也就不存在什么泛型擦除的問題了,,因?yàn)镵otlin在編譯之后會(huì)直接使用實(shí)參替代內(nèi)聯(lián)方法中泛型部分的代碼。

簡(jiǎn)單點(diǎn)來說,,就是Kotlin是允許將內(nèi)聯(lián)方法中的泛型進(jìn)行實(shí)化的,。

那么具體該怎么寫才能將泛型實(shí)化呢?首先,,該方法必須是內(nèi)聯(lián)方法才行,,也就是要用inline關(guān)鍵字來修飾該方法,。其次,在聲明泛型的地方還必須加上reified關(guān)鍵字來表示該泛型要進(jìn)行實(shí)化,。示例代碼如下所示:

inline fun <reified T> instanceOf(value: Any) {

}
  • 1
  • 2
  • 3

上述方法中的泛型T就是一個(gè)被實(shí)化的泛型,,因?yàn)樗鼭M足了內(nèi)聯(lián)函數(shù)和reified關(guān)鍵字這兩個(gè)前提條件。那么借助泛型實(shí)化,,我們到底可以實(shí)現(xiàn)什么樣的效果呢,?從方法名上就可以看出來了,這里我們借助泛型來實(shí)現(xiàn)一個(gè)instanceOf的效果,,代碼如下所示:

inline fun <reified T> instanceOf(value: Any) = value is T
  • 1

雖然只有一行代碼,,但是這里實(shí)現(xiàn)了一個(gè)Java中完全不可能實(shí)現(xiàn)的功能 —— 判斷參數(shù)的類型是不是屬于泛型的類型。這就是泛型實(shí)化不可思議的地方,。

那么我們?nèi)绾问褂眠@個(gè)方法呢,?在Kotlin中可以這么寫:

val result1 = instanceOf<String>("hello")
val result2 = instanceOf<String>(123)
// result1為true,result2為false
  • 1
  • 2
  • 3

可以看到,,第一行代碼指定的泛型是String,,參數(shù)是字符串"hello",因此最后的結(jié)果是true,。而第二行代碼指定泛型是String,,參數(shù)卻是數(shù)字123,因此最后的結(jié)果是false,。

除了可以做類型判斷之外,,我們還可以直接獲取到泛型的Class類型??匆幌孪旅娴拇a:

inline fun <reified T> genericClass() = T::class.java
  • 1

這段代碼就更加不可思議了,,genericClass()方法直接返回了當(dāng)前指定泛型的class類型。T.class這樣的語法在Java中是不可能的,,而在Kotlin中借助泛型實(shí)化功能就可以使用T::class.java這樣的語法了,。

然后我們就可以這樣調(diào)用:

val result1 = genericClass<String>()
val result2 = genericClass<Int>()
// result1為java.lang.String,result2為java.lang.Integer
  • 1
  • 2
  • 3

可以看到,,我們?nèi)绻付朔盒?code>String,,那么最終就可以得到java.lang.String的Class,如果指定了泛型Int,,最終就可以得到java.lang.Integer的Class,。

關(guān)于Kotlin泛型實(shí)化這部分的講解就到這里,現(xiàn)在我們重新回到LitePal上面,。講了這么多泛型實(shí)化方面的內(nèi)容,,那么LitePal到底如何才能利用這個(gè)特性進(jìn)行優(yōu)化呢?

回顧一下,,剛才我們查詢song表中id為1的這條記錄是這樣寫的:

val song = LitePal.find(Song::class.java, 1)
  • 1

這里需要傳入Song::class.java是因?yàn)橐嬷狶itePal去查詢song這張表中的數(shù)據(jù),。而通過剛才泛型實(shí)化部分的講解,,我們知道Kotlin中是可以使用T::class.java這樣的語法的,因此我在LitePal 3.0.0中擴(kuò)展了這部分特性,,允許通過指定泛型來聲明查詢哪張表中的內(nèi)容,。于是代碼就可以優(yōu)化成這個(gè)樣子了:

val song = LitePal.find<Song>(1)
  • 1

怎么樣,有沒有覺得代碼瞬間清爽了很多,?看起來比Java版的查詢還要更加簡(jiǎn)約,。

另外得益于Kotlin出色的類型推導(dǎo)機(jī)制,我們還可以將代碼改為如下寫法:

val song: Song? = LitePal.find(1)
  • 1

這兩種寫法效果是一模一樣的,,因?yàn)槿绻以?code>song變量的后面聲明了Song?類型,,那么find()方法就可以自動(dòng)推導(dǎo)出泛型類型,從而不需要再手動(dòng)進(jìn)行<Song>的泛型指定了,。

除了find()方法之外,我還對(duì)LitePal中幾乎全部的公有API都進(jìn)行了優(yōu)化,,只要是原來需要傳遞Class參數(shù)的接口,,我都增加了一個(gè)通過指定泛型來替代Class參數(shù)的擴(kuò)展方法。注意,,這里我使用的是擴(kuò)展方法,,而不是修改了原有方法,這樣的話兩種寫法你都可以使用,,全憑自己的喜好,,如果是直接修改原有方法,那么項(xiàng)目升級(jí)之后就可能會(huì)造成大面積報(bào)錯(cuò)了,,這是誰都不想看到的,。

那么這里我再向大家演示另外幾種CRUD操作優(yōu)化之后的用法吧,比如我想使用where條件查詢的時(shí)候就可以這樣寫:

val list = LitePal.where("duration > ?", "100").find<Song>()
  • 1

這里在最后的find()方法中指定了泛型<Song>,,得到的結(jié)果會(huì)是一個(gè)List<Song>集合,。

想要?jiǎng)h除song表中id為1的這條數(shù)據(jù)可以這么寫:

LitePal.delete<Song>(1)
  • 1

想要統(tǒng)計(jì)song表中的記錄數(shù)量可以這么寫:

val count = LitePal.count<Song>()
  • 1

其他一些方法的優(yōu)化也都是類似的,相信大家完全可以舉一反三,,就不再一一演示了,。

這樣我們就將LitePal新版本中的主要功能都介紹完了。當(dāng)然,,除了這些新功能之外,,我還修復(fù)了一些已知的bug,提升了整體框架的穩(wěn)定性,,如果這些正是你所需要的話,,那就趕快升級(jí)吧。

我沒學(xué)過LitePal怎么辦,?

本篇文章是寫給已經(jīng)有LitePal基礎(chǔ)的人看的,,幫助他們快速地升級(jí)到LitePal 3.0.0,。如果你之前并沒有學(xué)過LitePal,可以參考《第一行代碼 第2版》第6章中的內(nèi)容,,里面有非常詳盡的LitePal使用講解,。

另外也可以閱讀我寫的專欄《Android數(shù)據(jù)庫高手秘籍》,同樣對(duì)LitePal的各種使用方法進(jìn)行了詳細(xì)地剖析,。


關(guān)注我的技術(shù)公眾號(hào),,每天都有優(yōu)質(zhì)技術(shù)文章推送。關(guān)注我的娛樂公眾號(hào),,工作,、學(xué)習(xí)累了的時(shí)候放松一下自己。

微信掃一掃下方二維碼即可關(guān)注:

        

想對(duì)作者說點(diǎn)什么,?

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多