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