利用注解实现BindView、OnClick。

版权声明:转载请说明出处 https://blog.csdn.net/xuyonghong1122/article/details/80347201

此篇博客记录如何用annotation来实现View的自动绑定,及点击事件的绑定,不同于ButterKnife,本文采用的是Runtime注解,性能相比ButterKnife较低,ButterKnife采用的是编译注解,故性能更高。

BindView

声明注解

以BindView为例,首先需要声明注解

@Retention(AnnotationRetention.RUNTIME) //保存在内存中的字节码,JVM将在运行时也保留注解,因此可以通过反射机制读取注解的信息
@Target(AnnotationTarget.FIELD)//作用于成员变量、对象、属性(包括enum实例)
annotation class BindView(@IdRes val value: Int)

处理注解

object ViewBinder {

    fun bind(activity: Activity) {
        val clazz = activity.javaClass
        val fields = clazz.declaredFields
        fields.forEach {
            //判断注解是否存在
            if (it.isAnnotationPresent(BindView::class.java)) {
                //获取注解
                val viewId = it.getAnnotation(BindView::class.java).value
                val findView = clazz.getMethod("findViewById", Int::class.java)
                val view = findView.invoke(activity, viewId)
                it.isAccessible = true
                //赋值给注解标注的对象
                it.set(activity, view)
            }
        }
    }
}

使用注解

class MainActivity : AppCompatActivity() {
    @BindView(R.id.tv_bind_test)
    lateinit var testTv: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ViewBinder.bind(this)
        testTv.text = "注解成功注入"
    }
}

以上就可以成功完成对于View的绑定

OnClick

声明注解

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class OnClick(@IdRes val value: Int)

处理注解

object ViewBinder {

    fun bind(activity: Activity) {
        val clazz = activity.javaClass
        val fields = clazz.declaredFields
        fields.forEach {
            //判断注解是否存在
            if (it.isAnnotationPresent(BindView::class.java)) {
                //获取注解
                val viewId = it.getAnnotation(BindView::class.java).value
                val findView = clazz.getMethod("findViewById", Int::class.java)
                val view = findView.invoke(activity, viewId)
                it.isAccessible = true
                //赋值给注解标注的对象
                it.set(activity, view)
            }
        }

        val methods = clazz.declaredMethods
        methods.forEach { method ->
            if (method.isAnnotationPresent(OnClick::class.java)) {
                val viewId = method.getAnnotation(OnClick::class.java).value
                val findView = clazz.getMethod("findViewById", Int::class.java)
                val view = findView.invoke(activity, viewId)
                if (view != null) {
                    method.isAccessible = true
                    (view as View).setOnClickListener {
                        val types = method.genericParameterTypes
                        //判断方法参数长度
                        when (types.size) {
                            0 -> method.invoke(activity)
                            1 -> method.invoke(activity, it)
                        }
                    }
                }
            }
        }
    }
}

使用注解

    @OnClick(R.id.btn_click_test)
    private fun onMainTvClick(v: View) {
        Toast.makeText(MainActivity@ this, "click", Toast.LENGTH_SHORT).show()
    }

本篇博客不对注解及反射内容详细记录,后续有时间记得进行一次系统的记录。

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页