策略值 | 功能描述 |
---|---|
SOURCE | 注解只在源文件中保留,在编译期间删除。源码级别用于APT技术 |
CLASS | 注解只在编译期间存在于.calss文件中,运行时JVM不可获取注解信息。该策略值也是默认值。注意,在android中,编译后的dex文件获取不到注解信息。字节码级别用于字节码增加技术 |
RUNTIME | 运行时JVM可以获取注解信息,是最长注解持续期。运行时级别用于反射技术 |
枚举值 | 功能描述 |
---|---|
Type | 可以修饰类,接口,注解或枚举类型 |
FIELD | 可以修饰属性(成员变量),包括枚举常量 |
METHOD | 可以修饰方法 |
PAPAMETER | 可以修饰参数 |
CONSTRUCTOR | 可以修饰构造方法 |
LOCAL_VARIABLE | 可以修饰局部变量 |
ANNOTATION_TYPE | 可以修饰注解类 |
PACKAGE | 可以修饰包 |
以下三种我们不经常用到,知道大概使用场景即可
@Document注解用于将注解包含在javadoc中
@Inherited注解用于指明父类注解会被子类继承得到
@Repeatable注解用于声明标记的注解为可重复类型注解,可以在同一个地方多次使用
Kotlin版本,注意需要在class前边添加annotation,注解默认值需要使用kotlin版本下的类型(AnnotationTarget.TYPE,AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME)
annotation class MyClass(val value: String)
//使用
//使用
@Myclass("test")
Class Test{
}
Java版本,注意需要使用@interface,注解默认值需要使用java版本下的类型(ElementType.TYPE,RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Myclass {
String value();
}
//使用
@Myclass("test")
Class Test{
}
反射就是可以使用JDK提供的反射API进行反射调用。可以在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。对于任意一个对象,都能够调用它的任意方法和属性,并且能改变它的属性。是java被视为动态语言的关键
java反射机制主要提供了一下功能
根据方法名来进行反射操作
注解
/**
* 注解代替findViewById
*/
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class InjectView(@IdRes val value: Int)
注解处理
class InjectUtils {
companion object {
fun injectView(activity: Activity) {
val javaClass = activity.javaClass
val declaredFields = javaClass.declaredFields
for (field in declaredFields) {
//判断属性是否被InjectView注解声明
if (field.isAnnotationPresent(InjectView::class.java)) {
val injectView = field.getAnnotation(InjectView::class.java)
//获得了注解中设置的id
val id = injectView.value
val view: View = activity.findViewById(id)
//反射设置属性的至
field.isAccessible = true//设置访问权限,允许操作private的属性
try {
//反射赋值
field.set(activity, view)
} catch (e: IllegalAccessException) {
e.printStackTrace()
}
}
}
}
}
}
使用
class MainActivity : AppCompatActivity() {
@InjectView(R.id.tv)
val tv: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
InjectUtils.injectView(this)
tv?.text = "llllllllll"
}
}
注解
//定义注解区分长按还是点击
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class EventType(val listenerSetter: String, val listenerType: KClass<*>)
/**
* 注解代替setOnClickListener
*/
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@EventType(listenerType = View.OnClickListener::class, listenerSetter = "setOnClickListener")
annotation class InjectOnClick(@IdRes vararg val value: Int)
/**
* 注解代替setOnLongClickListener
*/
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@EventType(listenerType = View.OnLongClickListener::class, listenerSetter = "setOnLongClickListener")
annotation class InjectOnLongClick(@IdRes vararg val value: Int)
注解处理器
fun injectOnclick(activity: Activity) {
//遍历activity中的全部方法
activity.javaClass.declaredMethods.forEach { method ->
//遍历方法的所有注解,filter集合筛选函数,返回一个新的集合
method.annotations.filter { annotation ->
//筛选注解中含有EventType注解
annotation.annotationClass.java.isAnnotationPresent(EventType::class.java)
}.forEach { annotation ->//遍历注解中含有EventType注解
//获得EventType注解,从java获取的数据不确定不为空,所以单独提取出来好控制
val eventTypeAnnotation = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//版本控制
annotation.annotationClass.java.getDeclaredAnnotation(EventType::class.java)
} else {
null
}
if (eventTypeAnnotation != null) {
//EventType注解中listenerSetter listenerType值setOnclickListener
val listenerSetter = eventTypeAnnotation.listenerSetter
//加入listenerType.java是吧KClass转换成Class。
// newProxyInstance(classLoader,Interface Array,InvokeHandler)
Java 中第二参数是Class[] 所以必须装换
val listenerType = eventTypeAnnotation.listenerType.java
//添加访问权限,如果是私有方法,必须设置为true
method.isAccessible = true
val newProxyInstance =
Proxy.newProxyInstance(
listenerType.classLoader, arrayOf(listenerType)
) { proxy, _, args ->
//运行Activity中加OnClick或者OnLongClick注解的方法
// 此处判断长按监听事件,长按事件需要返回boolean值
if (listenerSetter == "setOnLongClickListener") {
method!!.invoke(activity, *(args ?: emptyArray()))
true
} else {
method!!.invoke(activity, *(args ?: emptyArray()))
}
}
//获取所有activity中加OnClick或者OnLongClick注解的value方法
val valueMethod = annotation.annotationClass.java.getDeclaredMethod("value")
//获取所有OnClick或者OnLongClick注解的value值
val viewIds = valueMethod.invoke(annotation) as IntArray
viewIds.forEach { viewId ->
val findViewById = activity.findViewById(viewId)
//获取View中setOnClickListener方法
val setOnListener = findViewById.javaClass.getMethod(listenerSetter, listenerType)
//运行View中setOnClickListener方法
setOnListener.invoke(findViewById, newProxyInstance)
}
}
}
}
}
使用
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
InjectUtils.injectOnclick(this)
}
@InjectOnClick(R.id.tv, R.id.tv1)
fun onClick(view: View) {
when (view.id) {
R.id.tv -> {
val intent = Intent(this, MainActivity2::class.java)
intent.putExtra("ceshi", "22222222")
startActivity(intent)
}
R.id.tv1 -> Log.d("MainActivity", "tv1")
else -> {
}
}
}
@InjectOnLongClick(R.id.tv, R.id.tv1)
fun onLongClick(view: View) {
when (view.id) {
R.id.tv -> Log.d("MainActivity", "长按tv")
R.id.tv1 -> Log.d("MainActivity", "长按tv1")
else -> {
}
}
}
}
注解
/**
* 注解代替跳转页面传参
*/
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class InjectAutoWired(val value: String = "")
注解处理器
fun injectAutoWried(activity: Activity) {
val javaClass = activity.javaClass
val intent = activity.intent
val extras = intent.extras ?: return
//获取文件中所有的属性
val declaredFields = javaClass.declaredFields
for (method in declaredFields) {
if (method.isAnnotationPresent(InjectAutoWired::class.java)) {
val autoWired = method.getAnnotation(InjectAutoWired::class.java)
val key = if (autoWired.value.isEmpty()) {
method.name
} else {
autoWired.value
}
if (extras.containsKey(key)) {
var obj = extras.get(key)
val componentType = method.type.componentType
if (method.type.isArray && Parcelable::class.java.isAssignableFrom(componentType)) {
var objs: Array = obj as Array
var objects = Arrays.copyOf(objs, objs.size, method.type as Class>?)
obj = objects
}
method.isAccessible = true
try {
//反射赋值
method.set(activity, obj)
} catch (e: IllegalAccessException) {
e.printStackTrace()
}
}
}
}
}
使用
class MainActivity2 : AppCompatActivity() {
@InjectView(R.id.tv)
val tv: TextView? = null
@InjectAutoWired("ceshi")
val ceshi: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
InjectUtils.injectView(this)
InjectUtils.injectOnclick(this)
InjectUtils.injectAutoWried(this)
tv?.text = ceshi
}
@InjectOnClick(R.id.tv, R.id.tv1)
fun onClick(view: View) {
when (view.id) {
R.id.tv -> {
val intent = Intent(this, MainActivity2::class.java)
intent.putExtra("ceshi", "22222222")
startActivity(intent)
}
R.id.tv1 -> Log.d("MainActivity", "tv1")
else -> {
}
}
}
@InjectOnLongClick(R.id.tv, R.id.tv1)
fun onLongClick(view: View) {
when (view.id) {
R.id.tv -> Log.d("MainActivity", "长按tv")
R.id.tv1 -> Log.d("MainActivity", "长按tv1")
else -> {
}
}
}
}
仅用于学习注解,反射相关知识