此篇博客记录如何用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()
}
本篇博客不对注解及反射内容详细记录,后续有时间记得进行一次系统的记录。