Kotlin關鍵字Reified在安卓開發中的用法

前言

Reified使(抽象的東西)更具體或更真實。 Kotlin中的這個關鍵字使Kotlin成爲用於Android開發的更好的語言。 共有3個明顯的優點,如下所示。

1.不再需要傳參數clazz

這也是大多數文章中最可能描述的一個比較明顯的優點,這裏也提及一下。如果希望具有一個用於啓動activity的擴展函數,則必須有一個作爲Class傳入的參數。

// Function
private fun <T : Activity> Activity.startActivity(
        context: Context, clazz: Class<T>) {
    startActivity(Intent(context, clazz))
}
// Caller
startActivity(context, NewActivity::class.java)

reified方法實現:

使用reified,簡化了泛型參數。

// Function
inline fun <reified T : Activity> Activity.startActivity(
        context: Context) {
    startActivity(Intent(context, T::class.java))
}
// Caller
startActivity<NewActivity>(context)

2.未知類型的安全轉換

在kotlin中,我們都知道as?,可以轉化成特定的類型或者不成功的時候返回null,我們認爲以下函數可以安全地獲取數據或返回null…

// Function
fun <T> Bundle.getDataOrNull(): T? {
    return getSerializable(DATA_KEY) as? T
}
// Caller
val bundle: Bundle = Bundle()
bundle.putSerializable(DATA_KEY, "Testing")
val strData: String? = bundle.getDataOrNull()
val intData: Int? = bundle.getDataOrNull() // Crash

然而,如果獲得的數據String不是期望的類型Int,則此函數將崩潰。因此,爲了安全地獲取數據,我們可以這樣修改代碼

// Function
fun <T> Bundle.getDataOrNull(clazz: Class<T>): T? {
    val data = getSerializable(DATA_KEY)
    return if (clazz.isInstance(data)) {
        data as T
    } else {
        null
    }
}
// Caller
val bundle: Bundle = Bundle()
bundle?.putSerializable(DATA_KEY, "Testing")
val strData: String? = bundle.getDataOrNull(String::class.java)
val intData: Int? = bundle.getDataOrNull(String::class.java) //Null

這不太好,不僅在函數編寫方式上,而且還需要傳遞額外的clazz參數

reified 方式實現

// Function
private inline fun <reified T> Bundle.getDataOrNull(): T? {
    return getSerializable(DATA_KEY) as? T
}
// Caller
val bundle: Bundle = Bundle()
bundle?.putSerializable(DATA_KEY, "Testing")
val strData: String? = bundle.getDataOrNull()
val intData: Int? = bundle.getDataOrNull() // Null

有了reified就很簡單了,而且類型轉換安全

3.不同的返回類型函數重載

假如有一個將dp計算爲Pixel並根據期望值返回Int或Float的函數。

fun Resources.dpToPx(value: Int): Float {
    return TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        value.toFloat(), displayMetrics)
}
fun Resources.dpToPx(value: Int): Int {
    val floatValue: Float = dpToPx(value)
    return floatValue.toInt()
}

然而,這會在編譯時導致錯誤。 原因是,Overload函數簽名只能因參數個數和類型而有所不同,不能根據返回類型。

reified 方式實現

用了reified,就可以模擬了

inline fun <reified T> Resources.dpToPx(value: Int): T {
    val result = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        value.toFloat(), displayMetrics)

    return when (T::class) {
        Float::class -> result as T
        Int::class -> result.toInt() as T
        else -> throw IllegalStateException("Type not supported")
    }
}
// Caller
val intValue: Int = resource.dpToPx(64)
val floatValue: Float = resource.dpToPx(64)

總結

從上面的3個例子中可以明顯看出,帶有relied的效果使Kotlin變得更好。

 

 

翻譯出自:How Reified Type makes Kotlin so much better  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章