Android Kotlin泛型工具类
【代码】Android Kotlin泛型工具类。
·
/**
* 获取泛型ViewModel的真实类型
*/
fun <T> Any.getViewModelClass(clz: Class<*>): Class<T> {
return this.getRealClass(ViewModel::class.java, clz)
}
/**
* 获取泛型Repository的具体类型
*/
fun <T> Any.getRepositoryClass(): Class<T> {
return this.getRealClass(BaseRepository::class.java, BaseViewModel::class.java)
}
/**
* 获取泛型的具体类型
* @param targetClz 目标类型,例如 BaseRepository、ViewModel
* @param dstClz 用于表示搜索结束,一般为泛型声明类本身 BaseVMActivity 、BaseViewModel
*/
fun <T> Any.getRealClass(targetClz: Class<*>, dstClz: Class<*>): Class<T> {
var clz: Class<*> = this.javaClass
var realType: Type? = null
while (true) {
val generic = clz.genericSuperclass
if (generic is ParameterizedType) {
val typeArguments = generic.actualTypeArguments
typeArguments.forEach {
if (it is Class<*> && targetClz.isAssignableFrom(it)) {
realType = it
return@forEach
}
}
}
clz = clz.superclass
if (clz == Any::class.java || clz == Object::class.java || clz == dstClz::class.java) break
}
if (realType == null) {
throw ClassCastException("${this.javaClass.name} 不是继承自 ${dstClz.name},或者${dstClz.name} 没有泛型类型")
} else {
return realType as Class<T>
}
}
/**
* 通过 layoutInflater 获取对应的 ViewBinding
*/
@JvmName("ViewBindingUtils")
fun <VB : ViewBinding> Any.inflateBindingWithGeneric(layoutInflater: LayoutInflater): VB {
return withGenericBindingClass(this) { clazz ->
clazz.getMethod("inflate", LayoutInflater::class.java).invoke(null, layoutInflater) as VB
}
}
/**
* 通过 ViewGroup 获取对应的 ViewBinding
*/
@JvmName("inflateWithGeneric")
fun <VB : ViewBinding> Any.inflateBindingWithGeneric(parent: ViewGroup): VB =
inflateBindingWithGeneric(LayoutInflater.from(parent.context), parent, false)
/**
* 获取ViewGroup对象的真实数据类型
*/
@JvmName("inflateWithGeneric")
fun <VB : ViewBinding> Any.inflateBindingWithGeneric(
layoutInflater: LayoutInflater,
parent: ViewGroup?,
attachToParent: Boolean
): VB = withGenericBindingClass(this) { clazz ->
clazz.getMethod(
"inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java
).invoke(null, layoutInflater, parent, attachToParent) as VB
}
/**
* 获取对象的真实数据类型
*/
private fun <VB : ViewBinding> withGenericBindingClass(any: Any, block: (Class<VB>) -> VB): VB {
var throwable: Throwable? = null
any.allParameterizedType.forEach { parameterizedType ->
parameterizedType.actualTypeArguments.forEach {
try {
val clazz = it as Class<*>
Logger.d("ViewBindingUtils", "当前泛型 Type 名称为:${clazz.name}")
if (clazz.name.endsWith("Binding")) {
Logger.d("ViewBindingUtils", "当前泛型参数是 ViewBinding,准备获取其真实类型")
return runCatching {
block.invoke(it as Class<VB>)
}.onFailure { e ->
throwable = e
}.getOrThrow()
}
} catch (e: Exception) {
Logger.e("ViewBindingUtils", "获取 ViewBinding 泛型实例异常", e)
e.printStackTrace()
}
}
}
throw IllegalArgumentException("ViewBinding 生成失败,请检查相关自定义View布局和代码是否有错误", throwable)
}
/**
* 获取对象中的全部 ParameterizedType
*/
private val Any.allParameterizedType: List<ParameterizedType>
get() {
val genericParameterizedType = mutableListOf<ParameterizedType>()
var genericSuperclass = javaClass.genericSuperclass
var superclass = javaClass.superclass
while (superclass != null) {
if (genericSuperclass is ParameterizedType) {
genericParameterizedType.add(genericSuperclass)
}
genericSuperclass = superclass.genericSuperclass
superclass = superclass.superclass
}
return genericParameterizedType
}
更多推荐

所有评论(0)