前言
大家对AOP应该都不陌生, 就算没有用过也肯定听说过,切面编程一直是一个热点的话题,AOP即Aspect Oriented Programming的缩写,习惯称为切面编程;与OOP(面向对象编程)万物模块化的思想不同,AOP则是将涉及到众多模块的某一类问题进行统一管理,AOP的优点是将业务逻辑与系统化功能高度解耦,让我们在开发过程中可以只专注于业务逻辑,其他一些系统化功能(如路由、日志、权限控制、拦截器、埋点、事件防抖等)则由AOP统一处理;
AspectJ简介
AOP是一种编程思想,或者说方法论,AspectJ则是专为AOP设计的一种语言,它支持原生的JAVA,可用于在java中处理AOP的相关问题;下面非常简单的描述下AspectJ中几个要点
Join Points
AspectJ中的切点,是AspectJ作用到具体某个位置的说明,主要包括三类:
Pointcuts
AspectJ中的切面(这种翻译不一定正确),由点及面,用于说明你需要hook哪一类问题,比如我需要hook所有的Activity的生命周期方法,则:
@Pointcut("execution(* android.app.Activity.on*(..))")
advice
Join Points和Pointcuts用来说明需要hook哪些位置或者流程,advice则用于hook之后指定需要做什么,包括:
before() 在切入点之前操作
after() 在切入点之后操作
around() 完全替换函数(可以手动再调用原函数)
around()用的会比较多,因为自由度高,其他的用around()都可以实现
AOP处理android中的重复点击
短时间的重复点击如果不做处理会带来不好的体验且可能引发问题(打开多个页面,多次提交,数据错乱),之前我写过一篇文章使用代理模式+反射来处理重复点击的问题:Android-如何优雅的处理重复点击 ,虽然这种方式能达到目的且还算灵活,但还是存在侵入性,对于业务逻辑不是完全透明,所以我们需要使用跟好的方式来处理;
AOP用于处理某一类独立的问题,非常契合屏蔽重复点击的需求,我们只需要hook住原先的点击事件(转确的说是点击事件后的处理流程),判断是不是重复点击,是则过滤掉不让它执行,否则就正常执行;
代码
在Android中进行AspectJ的实现,建议使用Hujiang大神的框架gradle_plugin_android_aspectjx,可以非常方便的集成和配置AspectJ在Android中的环境
集成
//root gradle dependencies { classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.1' } //app或module gradle apply plugin: 'android-aspectjx' //插件 compile 'org.aspectj:aspectjrt:1.8.9' //jar
AspectJ代码
@Aspect public class ClickFilterHook { private static Long sLastclick = 0L; private static final Long FILTER_TIMEM = 1000L; @Around("execution(* android.view.View.OnClickListener.onClick(..))") public void clickFilterHook(ProceedingJoinPoint joinPoint) { if (System.currentTimeMillis() - sLastclick >= FILTER_TIMEM) { sLastclick = System.currentTimeMillis(); try { joinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } } else { Log.e("ClickFilterHook", "重复点击,已过滤"); } } }
测试
//普通方式 ok mBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this,"有效点击",Toast.LENGTH_SHORT).show(); } }); //butterknife等IOC框架 ok @OnClick({R.id.btn}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.btn: Toast.makeText(MainActivity.this,"有效点击",Toast.LENGTH_SHORT).show(); break; } } //自定义view ok @BindView(R.id.tv_small_up) StrokeTextView mTvSmallUp; ... mTvSmallUp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this,"有效点击",Toast.LENGTH_SHORT).show(); } });
可以发现,我们处理重复点击的代码,对于原先的代码是没有任何耦合的,对于业务逻辑是完全透明,甚至业务逻辑代码里都没有体现,这一类问题就已经被处理好了,而且是全局的处理;
说一下上面的代码中几个点:
1、@Aspect:该注解用于标注使用Aspect的类,即你编写Aspec代码的类
2、@Around("...")
3、@Around注解用于标注hook之后的处理代码,我们这里使用Around是因为原函数(onClick)可能执行,也可能不执行;注解中的参数则对应Pointcuts
总结
我们通过面向切面思想来过滤掉了重复点击的事件,且高度解耦,可以看到代码非常简单,AOP重在理解这种思想且找准切入点;AOP在Android中还可以有非常多的应用,如:
后面有机会再聊这些应用;文章如有任何描述不正确或欠妥的地方,还请大家务必提出来我及时改正,免得误导更多盆友;
参考:深入理解Android之AOP
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对小牛知识库的支持。
目前,我已经开发了一个来使用带有搜索功能的显示数据列表(如image_1所示)。 我想在工具栏上添加过滤选项,类似于Youtube应用程序上的过滤器(参见image2)。有谁能给我线索轻松实施吗?用于UI设计和业务逻辑。 知道如何实现过滤器对话框窗口吗(参见image_3)?我应该只使用还是有其他更好的选项?
本文向大家介绍Spring Boot之AOP配自定义注解的最佳实践过程,包括了Spring Boot之AOP配自定义注解的最佳实践过程的使用技巧和注意事项,需要的朋友参考一下 前言 AOP(Aspect Oriented Programming),即面向切面编程,是Spring框架的大杀器之一。 首先,我声明下,我不是来系统介绍什么是AOP,更不是照本宣科讲解什么是连接点、切面、通知和切入点这些让
我收到了第三方客户的回复。我需要将一个特定的响应库存储到一个字符串中。 我想将加密的学生数据存储到字符串中
问题内容: SharedPreferences用于在Android中保存应用程序数据。 和两者都用来保存在共享偏好的变化。 如Android库中所述: 与commit()将其首选项同步写到持久性存储中的方式不同,apply()立即将其更改提交到内存中的SharedPreferences,但是启动对磁盘的异步提交,并且不会收到任何故障通知。如果此SharedPreferences上的另一个编辑器在a
根据您的经验,将大型模块导入组件时的最佳实践是什么。你能从下面的例子中告诉我是什么和原因吗? 或
我想在Spring Security过滤器中修改响应的内容。假设我想要的如下: 过滤器后面有一个REST服务,它检索字符串列表。如果我使用getOutputStream()进行写入,那么我可以在客户端上读取字符串列表(而不是字符串“Hello”)。如果我使用getWriter(),那么我会收到以下错误: 如何修改Spring安全过滤器中的响应内容?顺便说一句,我使用野蝇10,但它也应该适用于雄猫和
书中解释了在上面的代码中...“因为Widget和LoggingWidget中的doSomething方法都是同步的,所以在继续之前,每个方法都试图获取小部件上的锁。” 我运行了上面的代码来观察内部锁。上面的引文似乎暗示线程在Widget对象上获得了一个内在锁,但我观察到的是线程在LoggingWidget上获得了一个锁。我不知道如何核实收购数量,所以无法观察到这一点。 这本书是可以互换地使用lo
我在一个网站上使用angularjs,那里有一个搜索输入,可以过滤视图上的列表。此列表显示为一个ng-repeat,该ng-repeat具有搜索输入中的筛选器: 搜索输入: