Java怎么使用反射和动态代理实现一个View注解绑定库
java
view
使用反射结合动态代理实现一个View注解绑定库,支持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 { @BindView(R.id.button1) private Button button1; @BindView(R.id.button2) Button button2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MsInjector.inject(this); } @OnClick(R.id.button1) public void clickButton1() { Toast.makeText(this, "click button1", Toast.LENGTH_SHORT).show(); } @OnClick(R.id.button2) public void clickButton2() { Toast.makeText(this, "click button2", Toast.LENGTH_SHORT).show(); } @OnLongClick(R.id.button1) public boolean longClickButton1() { Toast.makeText(this, "long click button1", Toast.LENGTH_SHORT).show(); return false; } @OnLongClick(R.id.button2) public boolean longClickButton2() { Toast.makeText(this, "long click button2", Toast.LENGTH_SHORT).show(); return false; } }
登录后复制
以上是Java怎么使用反射和动态代理实现一个View注解绑定库的详细内容。更多信息请关注PHP中文网其他相关文章!
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章
R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前
By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前
By 尊渡假赌尊渡假赌尊渡假赌
刺客信条阴影:贝壳谜语解决方案
2 周前
By DDD
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前
By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前
By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处
