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