使用Kotlin高效地開(kāi)發(fā)Android App(五)完結(jié)篇

水邊騎馬.jpg

一. 單例

使用 Java 來(lái)編寫(xiě)單例模式的話捐祠,可以寫(xiě)出好幾種蒙秒。同樣,使用 Kotlin 也可以寫(xiě)出多種單例模式块请。在這里介紹的是一種使用委托屬性的方式來(lái)實(shí)現(xiàn)單例的寫(xiě)法娜氏。

首先,Kotlin 在語(yǔ)法層面上支持委托模式墩新。

委托模式是軟件設(shè)計(jì)模式中的一項(xiàng)基本技巧贸弥。在委托模式中,有兩個(gè)對(duì)象參與處理同一個(gè)請(qǐng)求海渊,接受請(qǐng)求的對(duì)象將請(qǐng)求委托給另一個(gè)對(duì)象來(lái)處理绵疲。委托模式是一項(xiàng)基本技巧,許多其他的模式臣疑,如狀態(tài)模式盔憨、策略模式、訪問(wèn)者模式本質(zhì)上是在更特殊的場(chǎng)合采用了委托模式朝捆。委托模式使得我們可以用聚合來(lái)替代繼承般渡。

對(duì)于一些很常見(jiàn)的屬性,雖然我們可以在每次需要它們的時(shí)候手動(dòng)地實(shí)現(xiàn)它們芙盘,但更好的方法是一次性全部實(shí)現(xiàn),然后放進(jìn)一個(gè)庫(kù)里面脸秽。換句話說(shuō)儒老,對(duì)其屬性值的操作不再依賴于其自身的getter()/setter()方法,而是將其托付給一個(gè)代理類记餐,從而每個(gè)使用類中的該屬性可以通過(guò)代理類統(tǒng)一管理驮樊。這種方式是委托屬性

在Kotlin的標(biāo)準(zhǔn)庫(kù)中有一系列的標(biāo)準(zhǔn)委托,not null屬性是其中之一囚衔。它會(huì)含有一個(gè)可null的變量并會(huì)在我們?cè)O(shè)置這個(gè)屬性的時(shí)候分配一個(gè)真實(shí)的值挖腰。如果這個(gè)值在被獲取之前沒(méi)有被分配,它就會(huì)拋出一個(gè)異常练湿。

當(dāng)然 by lazy 也可以實(shí)現(xiàn)單例猴仑,下面我們使用 not null 委托來(lái)實(shí)現(xiàn) Application 的單例。

class App : Application() {
    companion object {
        var instance: App by Delegates.notNull()
    }

    override fun onCreate() {
            super.onCreate()
            instance = this
    }
}

二. 封裝Extras

使用ExtrasDelegate來(lái)封裝Extras

import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import kotlin.reflect.KProperty

/**
 *
 * @FileName:
 *          com.safframework.delegate.extras.Extras.kt
 * @author: Tony Shen
 * @date: 2018-06-11 23:56
 * @version V1.0 <描述當(dāng)前版本功能>
 */
class ExtrasDelegate<out T>(private val extraName: String, private val defaultValue: T) {

    private var extra: T? = null

    operator fun getValue(thisRef: AppCompatActivity, property: KProperty<*>): T {
        extra = getExtra(extra, extraName, thisRef)
        return extra ?: defaultValue
    }

    operator fun getValue(thisRef: Fragment, property: KProperty<*>): T {
        extra = getExtra(extra, extraName, thisRef)
        return extra ?: defaultValue
    }

}

fun <T> extraDelegate(extra: String, default: T) = ExtrasDelegate(extra, default)

fun extraDelegate(extra: String) = extraDelegate(extra, null)

@Suppress("UNCHECKED_CAST")
private fun <T> getExtra(oldExtra: T?, extraName: String, thisRef: AppCompatActivity): T? =
        oldExtra ?: thisRef.intent?.extras?.get(extraName) as T?

@Suppress("UNCHECKED_CAST")
private fun <T> getExtra(oldExtra: T?, extraName: String, thisRef: Fragment): T? =
        oldExtra ?: thisRef.arguments?.get(extraName) as T?

封裝完之后肥哎,在MainActivity中傳遞參數(shù)跳轉(zhuǎn)到其他到Activity辽俗。

import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.safframework.delegate.R
import com.safframework.delegate.domain.User
import com.safframework.ext.click
import kotlinx.android.synthetic.main.activity_main.*

/**
 *
 * @FileName:
 *          com.safframework.delegate.activity.MainActivity.java
 * @author: Tony Shen
 * @date: 2018-06-13 12:03
 * @version V1.0 <描述當(dāng)前版本功能>
 */
class MainActivity:AppCompatActivity() {

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initViews()
    }

    private fun initViews() {

        text1.click{

            val intent = Intent(this@MainActivity, Demo4ExtrasDelegateActivity::class.java)
            val u = User("Tony","123456")
            intent.putExtra("user",u)
            intent.putExtra("string","just a test")
            startActivity(intent)
        }

        text2.click {

            val intent = Intent(this@MainActivity, Demo4PrefsDelegateActivity::class.java)
            startActivity(intent)
        }
    }
}

這里的click函數(shù),在使用Kotlin高效地開(kāi)發(fā)Android App(二)中已經(jīng)講述過(guò)篡诽,就不在重復(fù)講述崖飘。

Demo4ExtrasDelegateActivity接受從MainActivity中傳遞過(guò)來(lái)的參數(shù)。

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.safframework.delegate.domain.User
import com.safframework.delegate.extras.extraDelegate
import com.safframework.log.L

/**
 *
 * @FileName:
 *          com.safframework.delegate.activity.Demo4ExtrasDelegateActivity.java
 * @author: Tony Shen
 * @date: 2018-06-13 17:42
 * @version V1.0 <描述當(dāng)前版本功能>
 */
class Demo4ExtrasDelegateActivity: AppCompatActivity() {

    private val user: User? by extraDelegate("user")
    private val s:String? by extraDelegate("string")

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        L.json(user)
        L.i(s)
    }
}

所傳遞過(guò)來(lái)的任何對(duì)象類型杈女,都可以使用如下的方式獲取Extras朱浴。只要保證,extra的key正確即可达椰。

    private val user: User? by extraDelegate("user")
    private val s:String? by extraDelegate("string")

與Extra類似翰蠢,SharedPreferences也可以使用屬性委托的方式進(jìn)行封裝。

三. infix

中綴表達(dá)式是一種通用的算術(shù)或邏輯公式表示方法砰碴,操作符以中綴形式處于操作數(shù)的中間躏筏。中綴表達(dá)式允許我們使用一個(gè)單詞或字母來(lái)當(dāng)運(yùn)算符用(其本質(zhì)還是函數(shù)調(diào)用),忽略調(diào)用的點(diǎn)和圓括號(hào)呈枉。

Kotlin的中綴表達(dá)式趁尼,需要滿足以下條件:

  1. 使用infix修飾
  2. 只有一個(gè)參數(shù)
  3. 其參數(shù)不得接受可變數(shù)量的參數(shù)且不能有默認(rèn)值。

例如:

infix fun Int.add(i:Int):Int = this + i

infix fun Int.加(i:Int):Int = this + i

fun main(args: Array<String>) {

    println(5 add 10)
    println(5 加 10)
}

執(zhí)行結(jié)果:

15
15

在 Kotlin 中猖辫,使用中綴表達(dá)式最經(jīng)典的例子酥泞,莫過(guò)于使用kxdate來(lái)操作日期。
kxdate github地址:https://github.com/yole/kxdate

val twoMonthsLater = 2.months.fromNow
val yesterday = 1.days.ago

等價(jià)于:

val twoMonthsLater = 2 months fromNow
val yesterday = 1 days ago

由此可見(jiàn)啃憎,中綴表達(dá)式能讓代碼看起來(lái)更加接近于自然語(yǔ)言芝囤。

四. inline

Kotlin 天生支持函數(shù)式編程,高階函數(shù)和 lambda 是其一大特色辛萍。

使用高階函數(shù)會(huì)帶來(lái)一些運(yùn)行時(shí)間效率的損失:每一個(gè)函數(shù)都是一個(gè)對(duì)象悯姊,并且都會(huì)捕獲一個(gè)閉包。 即那些在函數(shù)體內(nèi)會(huì)被訪問(wèn)的變量贩毕。 內(nèi)存分配(對(duì)于函數(shù)對(duì)象和類)和虛擬調(diào)用會(huì)引入運(yùn)行時(shí)間開(kāi)銷悯许。

使用 inline 修飾的函數(shù),可以從編譯器角度將函數(shù)的函數(shù)體復(fù)制到調(diào)用處實(shí)現(xiàn)內(nèi)聯(lián)辉阶。

在很多情況下先壕,通過(guò)將 Lambda 表達(dá)式內(nèi)聯(lián)在使用處, 可以消除運(yùn)行時(shí)消耗瘩扼。

翻看 Kotlin 的 Standard.kt 可以發(fā)現(xiàn)它里面的函數(shù) with、apply垃僚、run集绰、let 等都使用了 inline。

再舉一個(gè)例子谆棺,對(duì) Closeable 進(jìn)行擴(kuò)展栽燕,讓它支持Java的try-with-resources特性包券。

inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    var closed = false
    try {
        return block(this)
    } catch (e: Exception) {
        closed = true
        try {
            this?.close()
        } catch (closeException: Exception) {
        }
        throw e
    } finally {
        if (!closed) {
            this?.close()
        }
    }
}

該方法已經(jīng)在 https://github.com/fengzhizi715/SAF-Kotlin-Utils

總結(jié)

本文是該系列最后一篇文章,未來(lái)不會(huì)整理零碎的開(kāi)發(fā)細(xì)節(jié)溅固,轉(zhuǎn)而會(huì)以體系化形式進(jìn)行整理。

該系列的相關(guān)文章:
使用Kotlin高效地開(kāi)發(fā)Android App(四)
使用Kotlin高效地開(kāi)發(fā)Android App(三)
使用Kotlin高效地開(kāi)發(fā)Android App(二)
使用Kotlin高效地開(kāi)發(fā)Android App(一)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侍郭,一起剝皮案震驚了整個(gè)濱河市询吴,隨后出現(xiàn)的幾起案子亮元,更是在濱河造成了極大的恐慌猛计,老刑警劉巖爆捞,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奉瘤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡煮甥,警方通過(guò)查閱死者的電腦和手機(jī)盗温,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)卖局,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)双霍,“玉大人,你說(shuō)我怎么就攤上這事洒闸。” “怎么了丘逸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)羞反。 經(jīng)常有香客問(wèn)我囤萤,道長(zhǎng),這世上最難降的妖魔是什么涛舍? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任富雅,我火速辦了婚禮,結(jié)果婚禮上没佑,老公的妹妹穿的比我還像新娘。我一直安慰自己鬼癣,他們只是感情好啤贩,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著痹屹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪暖庄。 梳的紋絲不亂的頭發(fā)上足画,一...
    開(kāi)封第一講書(shū)人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音医舆,去河邊找鬼象缀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛央星,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播毙石,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼徐矩!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起坪稽,我...
    開(kāi)封第一講書(shū)人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鳞骤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后篙梢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拂募,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年蔼水,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了录肯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡优炬,死狀恐怖厅贪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情养涮,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布懈凹,位于F島的核電站悄谐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏爬舰。R本人自食惡果不足惜寒瓦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一棒掠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦蜡镶、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至屯伞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間珠移,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工钧惧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勾习,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓乾颁,卻偏偏與公主長(zhǎng)得像粹舵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子眼滤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容