1.反射(Reflect)API
API | 描述 | 举例 |
---|---|---|
getClass | 获取类 | Class cls = this.getClass() |
getAnnotation(XX.class) | 获取注解 | clazz.getAnnotation()获取类之上的注解 获取方法之上的注解 field.getAnnotation()获取属性之上的注解 |
getMethod() | 获取方法 | |
invoke(xx, yy) | 执行方法 | |
getDeclaredMethods() | 获取所有方法 | |
getDeclaredFields() | 获取所有属性 | |
annotationType() | 获取注解类型 |
|
解释: getMethod()/getMethods()与 getDeclaredMethods()/getDeclaredMethods()的区别:
前者获取当前类以及它的父类的public方法
后者只能获取当前类的所有方法
获取属性同理
应用
给控件加注解,替换findViewById
1.新建一个控件注解
/**
* Created by everrise on 2019/9/3.
*/
@Target(ElementType.FIELD) //该注解只能作用在类之上
@Retention(RetentionPolicy.RUNTIME)//SOURCE做代码检测属于源码级, jvm在运行时通过反射的技术获取
public @interface InjectView {
//返回int类型的值
int value();
}
ElementType.TYPE:表示作用在类之上; ElementType.METHOD: 作用在方法之上;ElementType.FIELD:作用在属性之上
ElementType.CONSTRUCTOR:作用在构造方法之上;ElementType.ANNOTATION_TYPE:作用在另一个注解之上
ElementType.PACKAGE:作用在包之上 ; ElementType.PARAMETER:作用在属性之上
ElementType.LOCAL_VARIABLE:作用在局部属性之上
2.创建一个InjectManager类,并在BaseActivity的onCreate方法中调用
public class BaseActivity extends Activity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InjectManager.inject(this);
}
}
3.injectViews(activity);中通过反射注解找到需要的控件id并赋值给控件
public class InjectManager {
public static void inject(Activity activity) {
//布局的注入
injectLayout(activity);
//view注入
injectViews(activity);
}
private static void injectViews(Activity activity) {
//获取类
Class<? extends Activity> clazz = activity.getClass();
//获取所有属性
Field[] fields = clazz.getDeclaredFields();
for (Field field:fields) {
//获取属性的注解
InjectView injectView = field.getAnnotation(InjectView.class);
if(injectView !=null){
//获取注解的值
int viewId = injectView.value();
//获取findviewbyid
try {
Method method = clazz.getMethod("findViewById", int.class);
Object view = method.invoke(activity, viewId);
field.setAccessible(true);//设置私有属性可以访问
field.set(activity, view);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private static void injectLayout(Activity activity) {
//获取类
Class<? extends Activity> clazz = activity.getClass();
//获取类的注解
ContentView contentView = clazz.getAnnotation(ContentView.class);
//获取注解的值
int layoutId = contentView.value();//布局id
//获取方法setContentView
try {
Method method = clazz.getMethod("setContentView", int.class);
//执行方法
method.invoke(activity,layoutId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.MainActivity继承BaseActivity使用注解
@ContentView(R.layout.activity_main)
public class MainActivity extends BaseActivity {
@InjectView(R.id.btn)
private Button btn;
@InjectView(R.id.tv)
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
5.注解替换setContentView同理
@Target(ElementType.TYPE) //该注解只能作用在类之上
@Retention(RetentionPolicy.RUNTIME)//SOURCE做代码检测属于源码级, jvm在运行时通过反射的技术获取注解的值
public @interface ContentView {
//返回int类型的布局值
int value();
}
注:本文来自网易Android公开课。非原创,仅做学习记录,ths