Android kotlin 委托

1 類委托

interface Base {
    fun print()
}
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}
class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // 輸出 10
}

Derived 的超類型列表中的 by句表示b 將會在 Derived 中內部存儲。 并且編譯器將成轉發(fā)給 b 的所有 Base 的法。

2 委托屬性

class Example {
    var p: String by Delegate()
}

語法是: val/var <屬性名>: <類型> by <表達式>。

屬性對應的 get()(和 set() )會被委托給表達式的getValue() 和 setValue()。

第一個參數是 p 所在對象的引用、第二個參數保存了對 p屬性自身的描述;

class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
    return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
    println("$value has been assigned to '${property.name} in $thisRef.'")
}
}

對于只讀屬性(即 val 聲明的),委托必須提供名為 getValue 的函數,該函數接受以下參數:

thisRef 必須與屬性所有者類型(對于擴展屬性指被擴展的類型)相同或者是它的超類型。

property 必須是類型 KProperty<*>或其超類型。

這個函數必須返回與屬性相同的類型(或其類型)。

對于可變屬性(即 var 聲明的),委托必須額外提供 setValue 的函數,該函數接受以下參數:

thisRef 同 getValue() ;

property 同 getValue() ;

new value 必須和屬性同類型或者是它的超類型。

getValue() 或/和 setValue() 函數可以通過委托類的成員函數提供或者由擴展函數提供。 兩函數都需要 operator 關鍵字來標記。

委托類可以實現包含所需 operator 方法的 ReadOnlyProperty 或 ReadWriteProperty。

這倆接口是在 Kotlin 標準庫中聲明的:

interface ReadOnlyProperty<in R, out T> {
    operator fun getValue(thisRef: R, property: KProperty<*>): T
}
interface ReadWriteProperty<in R, T> {
    operator fun getValue(thisRef: R, property: KProperty<*>): T
    operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}

3 延遲屬性 Lazy

val lazyValue: String by lazy {
    "Hello"
}

延遲加載屬性(lazy property): 屬性值只在初次訪問時才會計算;

get()會執(zhí)行l(wèi)ambda表達式并記錄結果,后續(xù)的get方法將只返回結果。

var類型屬性不能設置為延遲加載屬性,因為在lazy中并沒有setValue(…)方法。

lazy操作符是線程安全的。如果在不考慮多線程問題或者想提高更多的性能,也可以使
用 lazy(LazyThreadSafeMode.NONE){ … } 。
在LazyThreadSafetyMode中聲明了幾種,[Lazy]實例在多個線程之間同步訪問的形式:

SYNCHRONIZED:鎖定,用于確保只有一個線程可以初始化[Lazy]實例。

PUBLICATION:初始化函數可以在并發(fā)訪問未初始化的[Lazy]實例值時調用幾次,,但只有第一個返回的值將被用作[Lazy]實例的值。

NONE:沒有鎖用于同步對[Lazy]實例值的訪問; 如果從多個線程訪問實例,是線程不安全的。此模式應僅在高性能至關重要,并且[Lazy]實例被保證永遠不會從多個線程初始化時使用。

class App : Application() {
    val database: SQLiteOpenHelper by lazy {
        MyDatabaseHelper(applicationContext)
    }

    override fun onCreate() {
        super.onCreate()
        val db = database.writableDatabase
    }
}

4 可觀察屬性(Observable)

Delegates.observable() 函數接受兩個參數:
第一個是初始化值,
第二個是屬性值變化事件的響應器(handler).

這種形式的委托,采用了觀察者模式,其會檢測可觀察屬性的變化,當被觀察屬性的setter()方法被調用的時候,響應器(handler)都會被調用(在屬性賦值處理完成之后)并自動執(zhí)行執(zhí)行的lambda表達式,同時響應器會收到三個參數:被賦值的屬性, 賦值前的舊屬性值, 以及賦值后的新屬性值。


class ViewModel(val db: MyDatabase) {
    var myProperty by Delegates.observable("") {
        d, old, new ->
        db.saveChanges(this, new)
    }
}

5 Map中映射值
在像解析 JSON 或者做其他“動態(tài)”事情中。把map映射到屬性

import kotlin.properties.getValue
class Configuration(map: Map<String, Any?>) {
    val width: Int by map
    val height: Int by map
    val dp: Int by map
    val deviceName: String by map
}

conf = Configuration(mapOf(
    "width" to 1080,
    "height" to 720,
    "dp" to 240,
    "deviceName" to "mydevice"
))

6 局部委托屬性
你可以將局部變量聲明為委托屬性。
memoizedFoo 只有someCondition滿足條件,第一調用才會初始化

fun example(computeFoo: () -> Foo) {
    val memoizedFoo by lazy(computeFoo)
    if (someCondition && memoizedFoo.isValid()) {
    memoizedFoo.doSomething()
}
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 前言 人生苦多,快來 Kotlin ,快速學習Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,669評論 9 118
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現,斷路器,智...
    卡卡羅2017閱讀 136,525評論 19 139
  • Kotlin 知識梳理系列文章 Kotlin 知識梳理(1) - Kotlin 基礎Kotlin 知識梳理(2) ...
    澤毛閱讀 2,856評論 0 6
  • (*  ̄)( ̄ *)同事聚餐
    2a6352fe24c1閱讀 193評論 0 0
  • 今天比昨天舒服很多,不過一大早就發(fā)現自己的詢盤相比同個店鋪的其它同事少之又少,很有來一億個產品的沖動。于是今天就想...
    昕棲息的小屋閱讀 285評論 0 0

友情鏈接更多精彩內容