Kotlin语言使用反射机制编写运行时View注入

Kotlin语言使用反射机制编写运行时View注入

标签(空格分隔): android 作者:陈小默 kotlin版本:1.0.3


Kotlin是一种基于JVM的语言,这种语言最令人着迷的一点的就能与Java语言互相调用。于是有些人就以为按照Java的用法就能写好Koltin的程序。可是,Kotlin毕竟也是一门独立的高级语言呀。其内部一些机制和Java还是有很大区别的。现在我们通过编写一个运行时View注入的例子来了解一下Kotlin的反射。 首先我们先定义一个注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
annotation class BindView(val value: Int)

这里我们首先定义一个类BaseViewHolder,这个类用来处理View的注入事件。因为该类要被继承,所以这里应该加上open关键字。

open class BaseViewHolder {
    fun bind(activity: Activity) {
       
    }
}

在类里我们添加了一个bind方法,这个方法的目的是用来实现注入操作,我们最后再来实现这个方法。

接下来我们实现一个MyViewHolder去继承BaseViewHolder

class MyViewHolder : BaseViewHolder() {
    @BindView(R.id.name) var  name: TextView? = null
    @BindView(R.id.phone) var phone: TextView? = null
    @BindView(R.id.email) var email: TextView? = null
    @BindView(R.id.show) var show: Button? = null
}

布局文件我就不说了,自行创建更改上面的id 接下来在Activity中我们调用注入方法并显示输入信息

class MainActivity : AppCompatActivity() {
    private var holder = MyViewHolder()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        holder.bind(this)
        holder.show?.setOnClickListener { v ->
            Toast.makeText(this@MainActivity,
                    """姓名:${holder.name?.text.toString()}
                    |手机:${holder.phone?.text.toString()}
                    |邮箱:${holder.email?.text.toString()}""".trimMargin(), Toast.LENGTH_SHORT).show()
        }
    }
}

好了,现在解释一下上述代码:第10行字符串表示方式是"""原生字符串"""里面的内容可以跨行且不需要转义,第11行和第12行前面的|代表前导字符,表示这一行从这里开始前面的空白字符都忽略不计。

目前我们的整个工程就算写好了。现在我们要回过头去实现注入方法,考虑一下,如果使用Java的反射机制应该如何实现注入。。。。。。嗯,应该是这个样子:

fun bind(activity: Activity) {
        val any = this

        this.javaClass.declaredFields.forEach { field ->
            field.isAccessible = true
            val ann = field.getAnnotation(BindView::class.java)
            if (ann != null) {
                val view = activity.findViewById(ann.value)
                field.set(any, view)
            }
        }
    }

我们运行一下试试。。。。。。没反应,对不对。这是因为Kotlin和Java采用的反射机制不同,而我们的MyViewHolder并不是Java文件我们看到的class.java是为了Kotlin能够调用Java文件增加的类信息。但是我们Kotlin文件的交互还要通过Java去进行操作吗?所以我们要使用Kotlin内部的反射机制。

不知道是我没有找到还是因为当前1.0.3版本不完整,我并没有找到属性操作的相关方法,但是我通过查看源码扩展了常用的方法,第一个是任何类型都可以使用的获得Koltin类信息的方法,第二个是获得相应类型的全部注解(java8允许一个属性存在多个同类型的注解)第三个就是我们常用的获得获得属性上一个注解,随后一个方法是扩展的属性set方法

fun Any.kotlin() = this.javaClass.kotlin

fun KProperty1<*, *>.getAnnotations(type: KClass<*>): List<Annotation>? {
    return this.annotations.filter { ann ->
        ann.annotationClass == type
    }.toList()
}

fun <T : Annotation> KProperty1<*, *>.getAnnotation(type: KClass<T>): T? {
    val list = getAnnotations(type)
    return if (list != null) {
        list[0] as T
    } else {
        null
    }
}

fun KProperty1<Any, Any?>.set(any: Any, value: Any?) {
    (this as KMutableProperty1<Any, Any?>).set(any, value)
}

将这些扩展置于同级别包下即可

现在我们再来实现注入方法

    fun bind(activity: Activity) {
        val any = this
        any.kotlin().memberProperties.forEach { mem ->
            mem.isAccessible = true
            val ann = mem.getAnnotation(BindView::class)
            if (ann != null) {
                val view = activity.findViewById(ann.value)
                mem.set(any, view)
            }
        }
    }

现在一个Kotlin的注解就成了

转载于:https://my.oschina.net/oschenxiaomo/blog/733152

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值