Java注解应用场景

注解有三种级别,注解的保留级别不同,对注解的使用场景自然不同,
源码级别: 1.APT 在编译期能够获取注解与注解声明的类,包括类中的 所有成员信息,一般用于生成额外的辅助类.
2.可以提供IDE语法检查,取代枚举的使用
字节码: 1.在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。
2.对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解(这块还没用应用实例)
运行期: 在程序运行期间,通过反射技术动态获取注解与其元素,从而完成不同的逻辑判断 应用场景(自动注入一个View的findViewById操作)
下面介绍:源码级别提供IDE语法检查案例:

public enum Teacher {
    LIGUOJING,ZHUPENG
}

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {1,2})//提供语法检查需要传递的值
public @interface Teacher2 {
}

public class IdeTest {
    /*
    * 我们定义的test方法,只能传递 LIGUOJING 和 ZHUPENG其中一个,为了进行内存优化
    * 我们现在不使用枚举,则定义方法为:
    * */
    private static final int LIGUOJING = 1;
    private static final int ZHUPENG = 2;

//    然而此时,调用test2方法由于采用基本数据类型int,将无法进行类型限定。
//    此时使用@IntDef增加自定义注解:
    public void test2(int t){
        test3(LIGUOJING);
        test3(ZHUPENG);
        test3(3);//IDE 提供语法检查,3 不符合语法规范,但是编译运行还是没有问题
    }
    // test3方法提供了语法检查,传递的int值必须是@Teacher2里面定义的
    public void test3(@Teacher2 int t){
    }
    public void test(Teacher teacher){
    }
}

在程序运行期间,通过反射技术动态获取注解,并自动完成findViewById操作和成员变量的赋值

public class MainActivity extends AppCompatActivity {
    @Inject(resId = R.id.tvText)
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        InjectUtils.injectViewId(this);
        textView.setText("通过注解进行findViewById操作");
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, MainActivity2.class);
                // 这些传递的值,需要在MainActivity2中,通过注解进行赋值操作
                intent.putExtra("zhupeng", "失恋好了吗");
                intent.putExtra("userId", 110);
                intent.putExtra("user", new User("李国菁", 29));
                intent.putExtra("userArray",new User[]{new User("李菁",31),new User("李国伟",22)});
                startActivity(intent);
            }
        });
    }
}

Inject 和 Autowired注解类代码

@Target(ElementType.FIELD)//作用在成员变量上
@Retention(RetentionPolicy.RUNTIME)// 保留在运行时期
public @interface Inject {
    @IdRes int resId();// 其中IdRes 的意思是:必须指定这个int 值为 R.id.xx 类型
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
    String value() default "";
}

Javabean类

public class User implements Parcelable {
    private String name;
    private int age;

    public User(String name,int age){
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    protected User(Parcel in) {
        name = in.readString();
        age = in.readInt();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

跳转后MainActivity2赋值

public class MainActivity2 extends AppCompatActivity {
    @Inject(resId = R.id.tvText)
    private TextView textView;
    @Autowired(value = "zhupeng")
    private String zhupeng;
    @Autowired
    private int userId;
    @Autowired
    private User user;
    @Autowired
    private User[] userArray;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        InjectUtils.injectViewId(this);
        InjectUtils.injectAutowired(this);
//      InjectUtils.injectIntentValue(this); 这个方法只能赋值String 和int值
        String str = "";
        for (int i = 0; i <userArray.length ; i++) {
            str+= userArray[i];
        }
        textView.setText(zhupeng + userId + user + "\n" + str);
    }
}

InjectUtils 这块是重点内容,需要仔细查看

public class InjectUtils {
    public static void injectViewId(Activity activity) {
        if (activity == null) {
            throw new RuntimeException("Activity is not null");
        }
        Class<? extends Activity> clazz = activity.getClass();
        //获取所有的成员变量,包括 private类型的成员变量
        Field[] allFields = clazz.getDeclaredFields();
        for (Field field : allFields) {
            // 判断该字段上面是否有注解
            boolean isPresent = field.isAnnotationPresent(Inject.class);
            if (isPresent) {
                // 获取字段上的注解
                Inject fieldAnnotation = field.getAnnotation(Inject.class);
                int viewId = fieldAnnotation.resId();
                View view = activity.findViewById(viewId);
                // 修改 private 成员变量的值,必须加上下面这句,否则会有问题
                field.setAccessible(true);
                // 给这个字段进行赋值
                try {
                    field.set(activity, view);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static void injectIntentValue(Activity activity) {
        if (activity == null) {
            throw new RuntimeException("Activity is not null");
        }
        Class<? extends Activity> clazz = activity.getClass();
        //获取所有的成员变量,包括 private类型的成员变量
        Field[] allFields = clazz.getDeclaredFields();
        for (Field field : allFields) {
            // 判断该字段上面是否有注解
            boolean isPresent = field.isAnnotationPresent(Autowired.class);
            if (isPresent) {
                // 获取字段上的注解
                Autowired fieldAnnotation = field.getAnnotation(Autowired.class);
                String key = TextUtils.isEmpty(fieldAnnotation.value()) ? field.getName() : fieldAnnotation.value();
                try {
                    Object value = getValue(field.getType(), activity, key);
                    field.setAccessible(true);
                    field.set(activity, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static Object getValue(Class clazz,Activity activity,String key){
        System.out.println("clazz : " + clazz);
        if (clazz == String.class){
            return activity.getIntent().getStringExtra(key);
        }else if (clazz == int.class){
            return activity.getIntent().getIntExtra(key,0);
        }
        return new Object();
    }

    public static void injectAutowired(Activity activity) {
        if (activity == null) {
            return;
        }
        Intent intent = activity.getIntent();
        if (intent == null) {
            return;
        }
        // intent 传递参数,都是把参数封装在 bundle里面进行传输的
        Bundle bundle = intent.getExtras();
        if (bundle == null) {
            return;
        }
        Class<? extends Activity> clazz = activity.getClass();
        // 获取所有的成员变量
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            // 判断成员变量上有没有Autowired的注解
            if (field.isAnnotationPresent(Autowired.class)) {
                Autowired autowired = field.getAnnotation(Autowired.class);
                String key = TextUtils.isEmpty(autowired.value()) ? field.getName() : autowired.value();
                // 获取key 值对应的 value
                Object obj = bundle.get(key);
                field.setAccessible(true);
                try {
                    /*
                    * 对于数组类型实现 Parcelable 接口的需要单独处理
                    * */
                    // 获取该字段的真正类型
                    Class<?> type = field.getType();
                    System.out.println("lgj type :" + type);
                    // 获取数组单个元素类型
                    Class<?> componentType = type.getComponentType();
                    // type 类型是数组,并且是 Parcelable 子类数组
                    if (type.isArray() && Parcelable.class.isAssignableFrom(componentType)){
                        Object[] objs = (Object[]) obj;
                        Object[] objects = Arrays.copyOf(objs, objs.length, (Class<? extends Object[]>) type);
                        obj = objects;
                    }
                    // 通过反射进行赋值运算
                    field.set(activity, obj);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

通过注解然后执行一个控件的OnClick事件

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@EventType(listenerSetter = "setOnClickListener", listenerType = View.OnClickListener.class)
public @interface Click {
    @IdRes int[] value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface EventType {
    String listenerSetter();
    Class listenerType();
}

public class MainActivity3 extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        ClickUtils.injectEvent(this);
    }
    @Click({R.id.tv,R.id.tv2})
    public void test(View view){
        Toast.makeText(this,"通过注解,来执行onClick事件",Toast.LENGTH_SHORT).show();
    }
}

重点代码

public class ClickUtils {
    public static void injectOnClick(final Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (final Method declaredMethod : declaredMethods) {
            boolean isPresent = declaredMethod.isAnnotationPresent(Click.class);
            if (isPresent) {
                Click annotation = declaredMethod.getAnnotation(Click.class);
                int[] value = annotation.value();
                for (int i = 0; i < value.length; i++) {
                    // 找到这个view
                    View view = activity.findViewById(value[i]);
                    // 然后设置点击事件,通过反射调用,对应的方法
                    view.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            try {
                                declaredMethod.invoke(activity, v);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }

            }
        }
    }

    //  自己在这瞎捉摸写的
    public static void injectOnClickProxy(final Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (final Method declaredMethod : declaredMethods) {
            boolean isPresent = declaredMethod.isAnnotationPresent(Click.class);
            if (isPresent) {
                Click annotation = declaredMethod.getAnnotation(Click.class);
                int[] value = annotation.value();
                for (int i = 0; i < value.length; i++) {
                    final View view = activity.findViewById(value[i]);
                    try {
                        final Method viewClick = view.getClass().getDeclaredMethod("setOnClickListener", View.class);
//                        viewClick.invoke(view,view);
                        Object obj = Proxy.newProxyInstance(ClickUtils.class.getClassLoader(), new Class[]{View.OnClickListener.class}, new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                return viewClick.invoke(view, args);
                            }
                        });
                        System.out.println("lgj obj :" + obj);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }

            }
        }
    }
    public static void injectEvent(final Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            // 获取方法上的所有注解
            Annotation[] annotations = method.getAnnotations();
            for (Annotation annotation : annotations) {
                //System.out: lgj annotation:@com.lgj.xxkt.动态代理.Click(value=[2131165423, 2131165424])
                System.out.println("lgj annotation:" + annotation);
                //注解类型
                Class<? extends Annotation> annotationType = annotation.annotationType();
//                lgj annotationType:interface com.lgj.xxkt.动态代理.Click
                System.out.println("lgj annotationType:" + annotationType);
                if (annotationType.isAnnotationPresent(EventType.class)) {
                    EventType eventType = annotationType.getAnnotation(EventType.class);
                    //setOnClickListener
                    String setOnClickListener = eventType.listenerSetter();
                    // OnClickListener.class
                    Class listenerType = eventType.listenerType();


                    // 获取 方法上注入view 的ID
                    Click annotationClick = (Click) annotation;
                    int[] viewIds = annotationClick.value();
                    method.setAccessible(true);

                    // 需要对Activity进行代理
                    MyInvocationHandler<Activity> handler = new MyInvocationHandler<>(activity, method);
                    Object listenerProxy = Proxy.newProxyInstance(listenerType.getClassLoader(),
                            new Class[]{listenerType}, handler);
//                    System.out.println("listenerProxy : " + listenerProxy);
                    for (int i = 0; i < viewIds.length; i++) {
                        // 获取当前Activity的view (赋值)
                        View view = activity.findViewById(viewIds[i]);
                        try {
                            // 获取指定的方法  getDeclaredMethod 和 getMethod 的区别
                            // getDeclaredMethod 可以拿反射类中的公共方法 私有方法 保护方法 但不能获取继承的方法
                            // getMethod 可以拿到反射类及其父类中的所有公共方法
                            Method setter = view.getClass().getMethod(setOnClickListener, listenerType);
                            // 执行方法
                            setter.invoke(view,listenerProxy);//执行setOnclickListener里面的回调 onclick方法
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                }
            }
        }

    }

    static class MyInvocationHandler<T> implements InvocationHandler {
        private Method method;
        private T target;

        public MyInvocationHandler(T target, Method method) {
            this.target = target;
            this.method = method;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return this.method.invoke(target, args);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值