前言
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變得更好。