download:2021助理高薪-拉钩产品经理高薪训练营使用反射和动静代理实现一个View注解绑定库
反对的功能@ContentView 绑定layout 代替setContentView()@BindView 绑定View 代替findViewById()@OnClick 绑定点击事件 代替setOnClickListener()@OnLongClick 绑定长按事件 代替setOnLongClickListener()
代码注解类@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface ContentView {
int value();}复制代码@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface BindView {
int value();}复制代码@Target(ElementType.ANNOTATION_TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface OnEvent {
//订阅形式String setCommonListener();//事件源对象Class<?> commonListener();}复制代码@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@OnEvent(setCommonListener = "setOnClickListener",
commonListener = View.OnClickListener.class)public @interface OnClick {
int value();}复制代码@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@OnEvent(setCommonListener = "setOnLongClickListener",
commonListener = View.OnLongClickListener.class)public @interface OnLongClick {
int value();}复制代码实现类public class MsInjector {
public static void inject(Object object) { injectContentView(object); injectView(object); injectEvent(object);}private static void injectContentView(Object object) { Class<?> clazz = object.getClass(); //获取到ContentView注解 ContentView contentView = clazz.getAnnotation(ContentView.class); if (contentView == null) { return; } //获取到注解的值,也就是layoutResID int layoutResID = contentView.value(); try { //反射出setContentView方法并调用 Method method = clazz.getMethod("setContentView", int.class); method.invoke(object, layoutResID); } catch (Exception e) { e.printStackTrace(); }}private static void injectView(Object object) { Class<?> clazz = object.getClass(); //获取到所有字段并遍历 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); //获取字段上的BindView注解 BindView bindView = field.getAnnotation(BindView.class); if (bindView == null) { continue; } //获取到viewId int viewId = bindView.value(); try { //通过反射调用findViewById失去view实例对象 Method method = clazz.getMethod("findViewById", int.class); Object view = method.invoke(object, viewId); //赋值给注解标注的对应字段 field.set(object, view); } catch (Exception e) { e.printStackTrace(); } }}private static void injectEvent(Object object) { Class<?> clazz = object.getClass(); //获取到当前页年一切办法并遍历 Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { declaredMethod.setAccessible(true); //获取方法上的所有注解并遍历 Annotation[] annotations = declaredMethod.getDeclaredAnnotations(); for (Annotation annotation : annotations) { //获取注解本身 Class<? extends Annotation> annotationType = annotation.annotationType(); //获取注解上的OnEvent注解 OnEvent onEvent = annotationType.getAnnotation(OnEvent.class); if (onEvent == null) { continue; } //拿到注解中的元素 String setCommonListener = onEvent.setCommonListener(); Class<?> commonListener = onEvent.commonListener(); try { //因为上边没有明确获取是哪个注解,所以这里需要使用反射获取viewId Method valueMethod = annotationType.getDeclaredMethod("value"); valueMethod.setAccessible(true); int viewId = (int) valueMethod.invoke(annotation); //通过反射findViewById获取到对应的view Method findViewByIdMethod = clazz.getMethod("findViewById", int.class); Object view = findViewByIdMethod.invoke(object, viewId); //通过反射获取到view中对应的setCommonListener方法 Method viewMethod = view.getClass().getMethod(setCommonListener, commonListener); //使用动静代理监听回调 Object proxy = Proxy.newProxyInstance( clazz.getClassLoader(), new Class[]{commonListener}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //最终执行被标注的方法 return declaredMethod.invoke(object, null); } } ); //调用view的setCommonListener方法 viewMethod.invoke(view, proxy); } catch (Exception e) { e.printStackTrace(); } } }}}复制代码使用@ContentView(R.layout.activity_main)public class MainActivity extends AppCompatActivity {
...