Kotlin中的lateinit、lazy關(guān)鍵字

前言

Kotlin 是一種在 Java 虛擬機(jī)上運行的靜態(tài)類型編程語言,被稱之為 Android 世界的Swift,在Google I/O 2017中,Google 宣布 Kotlin 成為 Android 官方開發(fā)語言

img.jpg

lateinit關(guān)鍵字的作用

修飾成員變量,表示稍后對其進(jìn)行初始化,否則直接定義成員變量不初始化,編譯器會提示錯誤,局部變量在定義時不初始化不會有錯誤提示,這里只討論成員變量

  • 不能修飾基本數(shù)據(jù)類型,比如Int Byte Long Float
  • 只能修飾變量,不能修飾不可變屬性var
  • 可空類型的屬性不能使用lateinit修飾
  • 可以使用isInitialized檢查是否已經(jīng)做了初始化
var value:String //提示錯誤 需要初始化或者抽象
val value:String //提示錯誤 需要初始化或者抽象
lateinit var value:String //正確
lateinit val value:String //提示錯誤,不能修飾不可變屬性
lateinit var value:String? //提示錯誤,不能修飾可空類型的屬性
lateinit var value:Int //錯誤,不能修飾基本數(shù)據(jù)類型

lateinit關(guān)鍵字的使用

當(dāng)你需要定義一個成員變量,然后使用依賴注入的方式對其進(jìn)行初始化

@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory

或者說你只需要對其進(jìn)行成員聲明,而在過后的代碼中對其進(jìn)行初始化

class LoginActivity : DaggerAppCompatActivity() {

    private lateinit var loginViewModel: LoginViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.atctivity_login)
        loginViewModel = viewModelFactory.obtainViewModel<LoginViewModel>(this)
    }
}

但是這樣存在一個問題,lateinit 相當(dāng)于是和編譯器進(jìn)行了一個約定,在稍后對其進(jìn)行初始化,但如果沒有對其初始化,調(diào)用時就會拋出異常

class LoginActivity : DaggerAppCompatActivity() {

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory

    private lateinit var loginViewModel: LoginViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.atctivity_login)
        loginViewModel.userInfo.observe(this, Observer {

        })
    }
}
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property loginViewModel has not been initialized

所以需要在使用之前進(jìn)行判斷,是否已經(jīng)做過了初始化,使用isInitialized可以以避免異常,但是無法避免沒有初始化造成的功能缺失,同樣的延遲初始化lazy就可以避免這個問題

if (::loginViewModel.isInitialized) {
    loginViewModel.userInfo.observe(this, Observer {

    })
}

by lazy的作用

by lazy(lamda)用于延遲加載屬性,并且只是在第一次使用這個屬性的時候才會執(zhí)行Lamda以初始化對象,后續(xù)直接使用不會再調(diào)用lamda,by lazy是可以節(jié)省性能的

  • by lazy只能對常量val使用,不能對var使用
  • by lazy的加載時機(jī)是在第一次使用此屬性的時候
  • by lazy默認(rèn)是線程安全的,通過雙重檢查鎖定來保證線程安全,也可以修改它的線程策略
  • by lazy可以對基本數(shù)據(jù)類型以及引用類型使用
private val value: Person by lazy { Person() }//正確
private var value: Person by lazy { Person() } //編譯錯誤

by lazy的使用

懶漢式的單例模式

由于by lazy{}用于屬性,只會在第一次使用這個屬性才會初始化,并且是默認(rèn)線程安全的,這個很容易讓人想到懶漢式的單例模式,也是只需要在第一次使用才初始化對象

class PersonInfo {

    companion object {
        val INSTANCE by lazy { PersonInfo() }
    }

}

PersonInfo.INSTANCE //使用

只在使用到的時候初始化控件

由于by lazy{}用于屬性,使用時才會初始化,我們可以想到在開發(fā)中我們會初始化很多控件預(yù)備使用,但有的控件并不是每次用戶都可以用到的,所以可以使用其優(yōu)化只在用到的時候再初始化節(jié)省空間

private val help: Button by lazy { findViewById<Button>(R.id.btn_login) }
private val sessionTimeOutDialog: Dialog by lazy {
    AlertDialog.Builder(this)
        .setTitle("")
        .setMessage("")
        .create()
}

歡迎關(guān)注Mike的簡書

Android 知識整理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容