注解

2022-08-30  本文已影响0人  内卷程序员

注解是 JDK5 之后的新特性,是一种特殊的注释,它为提供了在代码中添加信息的新的方式

注解定义

基本数据类型(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)
}

元注解

元注解,就是用来定义和实现注解的注解,一共有四种

元素类型 作用范围
ANNOTATION_TYPE 注解类型声明
CONSTRUCTOR 构造函数
FIELD 实例变量
LOCAL_VARIABLE 局部变量
METHOD 方法
PACKAGE
PARAMETER 方法参数或者构造函数的参数
TYPE 类(包含enmu)和接口(包含注解类型)
TYPE_PARAMETER 类型参数
TYPE_USER 类型的用图
元素类型 保留级别
RetentionPolicy.SOURCE 该类型的注解信息只会保留在.java源码里,编译的时候注解将被编译器丢弃,其功能是与编译器交互,比如用于代码检测,@Override,@SuppressWarings
RetentionPolicy.CLASS 该注解的注册信息会保留在.java源码里和.class文件里,在执行的时候,会被java虚拟机丢弃,不会加载到虚拟机中,主要用于编译时生成额外的文件,如XML,Java文件等,APT
RetentionPolicy.RUNTIME 运行时级别,注解存在源码,字节码与Java虚拟机中,可以通过反射机制读取注解的信息, 许多框架如OrmLite就是使用这个级别的注解

注解使用

  // 获取类型指定注解
  <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);
 }
}
上一篇下一篇

猜你喜欢

热点阅读