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  

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