通过注解,反射,动态代理实现butterknife的点击和长按

158 阅读1分钟

代码示例分析

通过简单的代码实现butterknife的功能,用来强化注解,反射,动态代理的理解和应用

1.调用用代码

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //掉用实现类
    Butterknife.bind(this);
}
@onclick({R.id.bt_7,R.id.bt_8})
public void onclick(View view){
    switch (view.getId()){
        case R.id.bt_7:
            Log.e("lzl","按钮7点击");
            break;
        case R.id.bt_8:
            Log.e("lzl","按钮8点击");
            break;
    }
}

@onlongclick({R.id.bt_7,R.id.bt_8})
public boolean onlongclick(View view){
    switch (view.getId()){
        case R.id.bt_7:
            Log.e("lzl","按钮7长按");
            break;
        case R.id.bt_8:
            Log.e("lzl","按钮8长按");
            break;
    }
    return false;
}

2.自定义注解

/**
 * 这个是注解的注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Envtype {
    String listenerSetter();
    Class ListenerType();
}
/**
*这个是点击事件注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Envtype(listenerSetter = "setOnClickListener", ListenerType = View.OnClickListener.class)
public @interface onclick {
    int[] value();
}
/**
 * 这个是长按注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Envtype(listenerSetter = "setOnLongClickListener",ListenerType = View.OnLongClickListener.class)
public @interface onlongclick {
    int[] value();
}

3.butterknif的实现类

public class Butterknife {

    public static void bind(MainActivity mainActivity) {
        //1.拿到class对象,
        Class<? extends MainActivity> mainclass = mainActivity.getClass();
        //2.获取到所有的方法
        Method[] methods= mainclass.getDeclaredMethods();
        //3.便利所有方法
        for (Method method : methods) {
            Annotation[] annotation = method.getAnnotations();
            //1.遍历方法上的所有注解
            for (Annotation annotation1 : annotation) {
                //2.获取注解的class对象
                Class<? extends Annotation> annotationType = annotation1.annotationType();
                //3.判断当前的注解是不是envtype注解。
                if(annotationType.isAnnotationPresent(Envtype.class)){
                    //4.是的话获取注解上的参数。
                    Envtype envtype = annotationType.getAnnotation(Envtype.class);
                    String listenerSetter = envtype.listenerSetter();
                    Class listenerType = envtype.ListenerType();

                    //5.通过反射调用方法获取注解里的参数
                    try {
                        Method valueMethod = annotationType.getDeclaredMethod("value");
                        //参数是哪个对象掉用此方法
                        int[] value = (int[]) valueMethod.invoke(annotation1);

                        method.setAccessible(true);
                        //6.通过动态代理生成listenerType对应的接口对象。
                        Object proxy = Proxy.newProxyInstance(mainActivity.getClassLoader(), new Class[]{listenerType}, new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
                                //此处掉用的是activity里的方法,所以第一个对象是activity
                                return method.invoke(mainActivity,args);
                            }
                        });
                        //7.找到对应的控件设置相应的回调
                        for (int i : value) {
                            View view = mainActivity.findViewById(i);
                            //获取控件的class文件,通过反射掉用里面的方法
                            Method setter = view.getClass().getMethod(listenerSetter,listenerType);
                            setter.invoke(view,proxy);
                        }
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }



                }
            }
        }
    }
}