浅析android中的依赖注入
这几年针对Android推出了不少View注入框架,例如ButterKnife。我们首先来了解一下使用这些框架有什么好处,其实好处很明显:它可以减少大量的findViewById以及setOnClickListener代码,简化了代码,让我们的代码看起来条理更清晰,可读性变强。 可能大多数对于这一类框架,都只是停留在用的阶段,但是作为一个程序员,我们有必要去了解它是如何实现的。其实它的原理也没有多复杂,用到了java中反射和注解的相关知识,所以对反射和注解了解不多的朋友可以先找一下相关资料了解一下。 关于注解,我推荐一篇文章(简单易懂)http://mp.weixin.qq.com/s/NwlIy_knmx4Es7kFnk0gRQ 今天的任务呢就是教大家如何一步一步简单的实现一个类似 ButterKnife的依赖注入的效果: 第一步:我们需要自定义注解,如下: //用于初始化view的 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface BindView { int value() default 0; } //用于绑定点击事件的 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface BindClick { int value() default 0; } 从上面的Target里面的值我们可以知道,这两个注解一个是作用于属性,一个是作用于方法的。这里提醒一下,如果如果只有一个参数成员,最好把参数名称设为value,这里可以补一句因为使用该注解时,value作为key可省略,在使用的时候比较方便。 第二步:设置注解 @BindView(R.id.button) private Button mButton; @BindView(R.id.textview) private TextView mTextView; @BindClick(R.id.button) private void onButtonClick(){ Toast.makeText(this,"Button被点击了",Toast.LENGTH_SHORT).show(); } @BindClick(R.id.textview) private void onTextViewClick(){ Toast.makeText(this,"TextView被点击了",Toast.LENGTH_SHORT).show(); } 第三步:获取注解,进行处理 public class InjectUtils { public static void inject(final Activity activity) { //遍历属性,对设置注解的view进行初始化 Class<Activity> activityClass= (Class<Activity>) activity.getClass(); Field fields[]=activityClass.getDeclaredFields(); for(Field field:fields){ if(field.isAnnotationPresent(BindView.class)){ int viewId=field.getAnnotation(BindView.class).value(); View view=activity.findViewById(viewId); try { //这一行代码是必须的,否则直接调用set方法不生效 field.setAccessible(true); field.set(activity,view); } catch (IllegalAccessException e) { e.printStackTrace(); } } } //遍历方法 将设置注解的方法绑定到相应的view的点击事件中 Method methods[]=activityClass.getDeclaredMethods(); for(final Method method:methods){ BindClick bindClick=method.getAnnotation(BindClick.class); if(bindClick!=null){ int viewId=bindClick.value(); activity.findViewById(viewId).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { //调用该方法 method.setAccessible(true); method.invoke(activity); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }); } } } } 第四步:其实上面已经完成了处理,我们只需要调用一下就可以了,像下面那样: setContentView(R.layout.activity_main); //必须放在setContentView后面 InjectUtils.inject(this); 下面,我们就可以运行一下项目,看看是不是达到我们的效果了。 项目地址:https://github.com/coder-xiaoshuai/AnnotationDemo.git
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
2017-08-01 iOS开发技巧 - 使用和定制开关控件(UISwitch)
2015-08-01 java基本数据类型转换成byte[]数组
2015-08-01 java中int,char,string三种类型的相互转换
2015-08-01 说一说ASCLL和Unicode
2015-08-01 Java中二进制、十进制、十六进制及ASCII码与String及字节数组与十六进制之间的转换