一、点击频控常规做
由于历史原因 ,FM项目中存在 多种方式 :
1)调用处分散实现
缺点:代码冗余 ,实现不统一 (如时间间隔频率不一样等等)
2)定义成工具类使用(如下 ClickUtils)
ClickUtils 工具类克服了1)中问题,但是也存在一些问题,如 每个调用处需要手动组合一个tag (一般是文件名+ 方法名 )。
有些人可能会剔除都是点击事件直接用viewId 不就可以了吗 ,如果使用viewId 势必要传一个View 进去,这样大大限制了使用场景 (目前 FM 已经使用DataBinding),这种方式被抛弃。
![3315418-b62a4cbd05883043.png](https://upload-images.jianshu.io/upload_images/3315418-b62a4cbd05883043.png)
如果想自动化生成tag 也有其他办法 :如 new Throwable().getStackTrace() ,缺点有一定性能损耗。
![3315418-e5629bdf2bc97781.png](https://upload-images.jianshu.io/upload_images/3315418-e5629bdf2bc97781.png)
二 、AOP+Annotation 实现
那有没有更简单的方式 去实现 :去冗余 、更简洁自动化 ,对应AOP+Annotation 实现方式应运而生。
原理简单如下 :通过Annotation 标注那些方法需要判断 ,同过AOP 方式找到@SingleClick 使用的切点 ,自动生成唯一的 tag (这里是文件名 + 行号 )
(1)时间间隔定值实现方式
1)Aspect 插件Android gradle 开发环境配置
![3315418-cf6df8d06a70c91f.png](https://upload-images.jianshu.io/upload_images/3315418-cf6df8d06a70c91f.png)
2)定义@SingleClick注解
![3315418-7b2379c543c2fb77.png](https://upload-images.jianshu.io/upload_images/3315418-7b2379c543c2fb77.png)
3)定义切点处理方法 类 SingleClickAspect
利用joint.S=sourceLocation 获取文件名 和 行号 ,组合成可唯一确认的tag ,到此功能完全实现。
![3315418-a14f3520a9a36033.png](https://upload-images.jianshu.io/upload_images/3315418-a14f3520a9a36033.png)
(2)时间间隔可设方式
1)定义带默认值方法注解
![3315418-6c440cab1366eed9.png](https://upload-images.jianshu.io/upload_images/3315418-6c440cab1366eed9.png)
2)对应修改SingleClickAspect修改
由于本次需要获取注解上的设定值 ,因而这里需要使用MethodSignature 方法,对照改写如下,使用方式 @SingleClick 或者@SingleClick(xxx)
![3315418-4d9435a2476279dd.png](https://upload-images.jianshu.io/upload_images/3315418-4d9435a2476279dd.png)
运行发现,Debug 版本没有问题 ,Release 版本 挂掉了 ,报错信息指出 :method 为null 。细想都是按照@SingleClick 注解找的,method 怎么能为空,而且项目中也对所有注解混淆进行了Keep ,因此将问题锁定在AOP 的实现上。
1)使用反编译工具jadx 查看Rebase 和Debug 版本后的代码 与插装之前做对比
观察的是AlbumShowViewModel::onMoreClick() 方法 ,debug 版本如下 :
![3315418-a83d0bd034931ea5.png](https://upload-images.jianshu.io/upload_images/3315418-a83d0bd034931ea5.png)
![3315418-0e268c983eab63f5.png](https://upload-images.jianshu.io/upload_images/3315418-0e268c983eab63f5.png)
2)导致method 为null的原因
对比release 版本和debug 版本知 ,插装时使用的是makeMethodSig ,第三个参数declaringType 传的就是class 名字 ,直接使用Class.forName(declaringType) 创建class ,由于插装后 ,release 版本类名混淆,导致这里发生异常 ,method 为null。
![3315418-7e54743980abdb93.png](https://upload-images.jianshu.io/upload_images/3315418-7e54743980abdb93.png)
3)解决方式
解决方式很简易 :keep 住使用@SingleClick注解的类即可
![3315418-c537c41550c9d589.png](https://upload-images.jianshu.io/upload_images/3315418-c537c41550c9d589.png)
综上两种方式问题,FM项目最终选择时间间隔定值方式作为最终方案。