注解
2022-08-30 本文已影响0人
内卷程序员
注解是 JDK5 之后的新特性,是一种特殊的注释,它为提供了在代码中添加信息的新的方式
注解定义
- 定义注解的时候需要@interface
- 参数的类型只能是public或者不写两种访问修饰符
- 注解参数定义类似于抽象方法声明,返回值就是其类型
- 注解参数必须有确切的值,要么在定义注解的默认值中指定,要么在使用注解时指定,注解参数的可支持数据类型 如下:
基本数据类型(int,float,boolean,byte,double,char,long,short)
String类型
Class类型
enum类型
Annotation类型
以上所有类型的数组
//运行时注解,并采用反射方法调用执行。
// 1.绑定控件注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Bind {
int value();
int[] parentId() default 0;
}
// 2.检查网络注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CheckNet {
//是一个空注解,用的时候直接标注
}
// 3.绑定事件注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OnClick {
int[] value();
//如果注解的参数有默认值,在使用的时候如果不需要赋值可以不写这个参数
int[] parentId() default 0;
}
// 4. 绑定布局
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ContentView {
int value();
//如果注解只有一个参数, 尽量使用value来表示参数,这样在使用的时候可以直接 @ContentView (R.id.xxx),而不需要使用@ContentView (value=R.id.xxx)
}
元注解
元注解,就是用来定义和实现注解的注解,一共有四种
- @Target :用来指定注解所适用的对象范围 (ElementType类型的数组)
元素类型 | 作用范围 |
---|---|
ANNOTATION_TYPE | 注解类型声明 |
CONSTRUCTOR | 构造函数 |
FIELD | 实例变量 |
LOCAL_VARIABLE | 局部变量 |
METHOD | 方法 |
PACKAGE | 包 |
PARAMETER | 方法参数或者构造函数的参数 |
TYPE | 类(包含enmu)和接口(包含注解类型) |
TYPE_PARAMETER | 类型参数 |
TYPE_USER | 类型的用图 |
- @Retention :表示需要在什么级别保存该注解信息
元素类型 | 保留级别 |
---|---|
RetentionPolicy.SOURCE | 该类型的注解信息只会保留在.java源码里,编译的时候注解将被编译器丢弃,其功能是与编译器交互,比如用于代码检测,@Override,@SuppressWarings |
RetentionPolicy.CLASS | 该注解的注册信息会保留在.java源码里和.class文件里,在执行的时候,会被java虚拟机丢弃,不会加载到虚拟机中,主要用于编译时生成额外的文件,如XML,Java文件等,APT |
RetentionPolicy.RUNTIME | 运行时级别,注解存在源码,字节码与Java虚拟机中,可以通过反射机制读取注解的信息, 许多框架如OrmLite就是使用这个级别的注解 |
- @Documented:表示将此注解包含在Javadoc中
- @Inherited:表示允许子类继承父类中的注解
注解使用
// 获取类型指定注解
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
//获取该类的所有注解
Annotation[] getAnnotations()
public class ViewInjectorImpl implements ViewInject {
private ViewInjectorImpl() {
}
public static ViewInjectorImpl mInstance;
public static ViewInjectorImpl getInstance() {
if (mInstance == null) {
synchronized (ViewInjectorImpl.class) {
if (mInstance == null) {
mInstance = new ViewInjectorImpl();
}
}
}
return mInstance;
}
@Override
public void inject(View view) {
injectObject(view, view.getClass(), new ViewFinder(view));
}
@Override
public void inject(Object handler, View view) {
injectObject(handler, view.getClass(), new ViewFinder(view));
}
@Override
public void inject(Activity activity) {
Class<?> clazz = activity.getClass();
// activity设置布局
try {
ContentView contentView = findContentView(clazz);
if (contentView != null) {
int layoutId = contentView.value();
if (layoutId > 0) {
Method setContentView = clazz.getMethod("setContentView", int.class);
setContentView.invoke(activity, layoutId);
}
}
} catch (Exception e) {
e.printStackTrace();
}
injectObject(activity, clazz, new ViewFinder(activity));
}
@Override
public View inject(Object fragment, LayoutInflater inflater, ViewGroup container) {
Class<?> clazz = fragment.getClass();
// fragment设置布局
View view = null;
ContentView contentView = findContentView(clazz);
if (contentView != null) {
int layoutId = contentView.value();
if (layoutId > 0) {
view = inflater.inflate(layoutId, container, false);
}
}
injectObject(fragment, clazz, new ViewFinder(view));
return view;
}
/**
* 从类中获取ContentView注解
*
* @param clazz
* @return
*/
private static ContentView findContentView(Class<?> clazz) {
return clazz != null ? clazz.getAnnotation(ContentView.class) : null;
}
public static void injectObject(Object handler, Class<?> clazz, ViewFinder finder) {
try {
injectView(handler, clazz, finder);
injectEvent(handler, clazz, finder);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 设置findViewById
*
* @param handler
* @param clazz
* @param finder
*/
@SuppressWarnings("ConstantConditions")
private static void injectView(Object handler, Class<?> clazz, ViewFinder finder) throws Exception {
// 获取class的所有属性
Field[] fields = clazz.getDeclaredFields();
// 遍历并找到所有的Bind注解的属性
for (Field field : fields) {
Bind viewById = field.getAnnotation(Bind.class);
if (viewById != null) {
// 获取View
View view = finder.findViewById(viewById.value(), viewById.parentId());
if (view != null) {
// 反射注入view
field.setAccessible(true);
field.set(handler, view);
} else {
throw new Exception("Invalid @Bind for "
+ clazz.getSimpleName() + "." + field.getName());
}
}
}
}
/**
* 设置Event
*
* @param handler
* @param clazz
* @param finder
*/
@SuppressWarnings("ConstantConditions")
private static void injectEvent(Object handler, Class<?> clazz, ViewFinder finder) throws Exception {
// 获取class所有的方法
Method[] methods = clazz.getDeclaredMethods();
// 遍历找到onClick注解的方法
for (Method method : methods) {
OnClick onClick = method.getAnnotation(OnClick.class);
OnItemClick onItemClick = method.getAnnotation(OnItemClick.class);
boolean checkNet = method.getAnnotation(CheckNet.class) != null;
if (onClick != null) {
// 获取注解中的value值
int[] views = onClick.value();
int[] parentIds = onClick.parentId();
int parentLen = parentIds == null ? 0 : parentIds.length;
for (int i = 0; i < views.length; i++) {
// findViewById找到View
int viewId = views[i];
int parentId = parentLen > i ? parentIds[i] : 0;
View view = finder.findViewById(viewId, parentId);
if (view != null) {
// 设置setOnClickListener反射注入方法
view.setOnClickListener(new MyOnClickListener(method, handler, checkNet));
} else {
throw new Exception("Invalid @OnClick for "
+ clazz.getSimpleName() + "." + method.getName());
}
}
}
if (onItemClick != null) {
// 获取注解中的value值
int[] views = onItemClick.value();
int[] parentIds = onItemClick.parentId();
int parentLen = parentIds == null ? 0 : parentIds.length;
for (int i = 0; i < views.length; i++) {
// findViewById找到View
int viewId = views[i];
int parentId = parentLen > i ? parentIds[i] : 0;
AdapterView view = (AdapterView) finder.findViewById(viewId, parentId);
if (view != null) {
// 设置setOnItemClickListener反射注入方法
view.setOnItemClickListener(new MyOnItemClickListener(method, handler, checkNet));
} else {
throw new Exception("Invalid @OnItemClick for "
+ clazz.getSimpleName() + "." + method.getName());
}
}
}
}
}
private static class MyOnClickListener implements View.OnClickListener {
private Method method;
private Object handler;
private boolean checkNet;
public MyOnClickListener(Method method, Object handler, boolean checkNet) {
this.method = method;
this.handler = handler;
this.checkNet = checkNet;
}
@Override
public void onClick(View v) {
if (checkNet && !NetStateUtil.isNetworkConnected(v.getContext())) {
Toast.makeText(v.getContext(), "网络错误!", Toast.LENGTH_SHORT).show();
return;
}
// 注入方法
try {
method.setAccessible(true);
method.invoke(handler, v);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static class MyOnItemClickListener implements AdapterView.OnItemClickListener {
private Method method;
private Object handler;
private boolean checkNet;
public MyOnItemClickListener(Method method, Object handler, boolean checkNet) {
this.method = method;
this.handler = handler;
this.checkNet = checkNet;
}
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
if (checkNet && !NetStateUtil.isNetworkConnected(v.getContext())) {
Toast.makeText(v.getContext(), "网络错误!", Toast.LENGTH_SHORT).show();
return;
}
// 注入方法
try {
method.setAccessible(true);
method.invoke(handler, parent, v, position, id);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//在BaseActivity中的onCreate中初始化。ViewInjectorImpl .inject(this);
@ContentView(R.layout.activity_main)
public class MainActivity extends BaseActivity {
// 绑定控件
@Bind(R.id.viewpager)
ViewPager viewpager;
// 绑定事件并检查网络
@OnClick(R.id.dialog)
@CheckNet
void showDialog(TextView tv) {
Intent intent = new Intent(getActivity(), DialogViewActivity.class);
startActivity(intent);
}
}