AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)

一、点击频控常规做

由于历史原因 ,FM项目中存在 多种方式  :

1)调用处分散实现 

缺点:代码冗余 ,实现不统一  (如时间间隔频率不一样等等)

2)定义成工具类使用(如下 ClickUtils)

      ClickUtils 工具类克服了1)中问题,但是也存在一些问题,如 每个调用处需要手动组合一个tag (一般是文件名+ 方法名 )。

       有些人可能会剔除都是点击事件直接用viewId 不就可以了吗 ,如果使用viewId 势必要传一个View 进去,这样大大限制了使用场景 (目前 FM 已经使用DataBinding),这种方式被抛弃。

AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第1张图片
图1 ClickUtils 定义

        如果想自动化生成tag 也有其他办法 :如 new Throwable().getStackTrace() ,缺点有一定性能损耗。

AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第2张图片
图2 通过 StackTrace 获取class 名和 行号

二 、AOP+Annotation 实现

       那有没有更简单的方式 去实现  :去冗余 、更简洁自动化  ,对应AOP+Annotation 实现方式应运而生。

       原理简单如下 :通过Annotation 标注那些方法需要判断  ,同过AOP 方式找到@SingleClick 使用的切点 ,自动生成唯一的 tag (这里是文件名 + 行号 )

(1)时间间隔定值实现方式

       1)Aspect 插件Android gradle 开发环境配置

AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第3张图片
图3 Aspect 插件 配置

       2)定义@SingleClick注解

AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第4张图片
图4 定义@SingleClick注解 

      3)定义切点处理方法 类 SingleClickAspect

         利用joint.S=sourceLocation 获取文件名 和 行号 ,组合成可唯一确认的tag ,到此功能完全实现。

AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第5张图片
图5 SingleClickAspect 定义

(2)时间间隔可设方式

        1)定义带默认值方法注解 

AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第6张图片
图6 定义带默认值方法注解 

       2)对应修改SingleClickAspect修改

       由于本次需要获取注解上的设定值 ,因而这里需要使用MethodSignature 方法,对照改写如下,使用方式 @SingleClick  或者@SingleClick(xxx) 

AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第7张图片
图7 修改后SingleClickAspect 定义

       运行发现,Debug 版本没有问题 ,Release 版本 挂掉了 ,报错信息指出 :method 为null 。细想都是按照@SingleClick 注解找的,method 怎么能为空,而且项目中也对所有注解混淆进行了Keep ,因此将问题锁定在AOP 的实现上。

   1)使用反编译工具jadx 查看Rebase  和Debug 版本后的代码 与插装之前做对比

   观察的是AlbumShowViewModel::onMoreClick()  方法 ,debug 版本如下 :

AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第8张图片
图 8 debug 版本插装后的代码
AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第9张图片
图 9 release 版本插装后的代码 

  2)导致method 为null的原因 

     对比release 版本和debug 版本知 ,插装时使用的是makeMethodSig ,第三个参数declaringType 传的就是class 名字 ,直接使用Class.forName(declaringType) 创建class ,由于插装后 ,release 版本类名混淆,导致这里发生异常 ,method 为null。

AOP+Annotation 应用—— 点击频率控制(防止快速点击多次)_第10张图片
图10 插装实现

3)解决方式 

        解决方式很简易 :keep 住使用@SingleClick注解的类即可

图11  解决方式


综上两种方式问题,FM项目最终选择时间间隔定值方式作为最终方案。

你可能感兴趣的:(AOP+Annotation 应用—— 点击频率控制(防止快速点击多次))