Android中AOP的应用实践之过滤重复点击

作者:uncochen 时间:2022-09-19 22:01:02 

前言

大家对AOP应该都不陌生, 就算没有用过也肯定听说过,切面编程一直是一个热点的话题,AOP即Aspect Oriented Programming的缩写,习惯称为切面编程;与OOP(面向对象编程)万物模块化的思想不同,AOP则是将涉及到众多模块的某一类问题进行统一管理,AOP的优点是将业务逻辑与系统化功能高度解耦,让我们在开发过程中可以只专注于业务逻辑,其他一些系统化功能(如路由、日志、权限控制、 * 、埋点、事件防抖等)则由AOP统一处理;

AspectJ简介

AOP是一种编程思想,或者说方 * ,AspectJ则是专为AOP设计的一种语言,它支持原生的JAVA,可用于在java中处理AOP的相关问题;下面非常简单的描述下AspectJ中几个要点

Join Points

AspectJ中的切点,是AspectJ作用到具体某个位置的说明,主要包括三类:

  • 函数(函数调用,函数执行,构造函数等)

  • 变量(变量get,变量set等)

  • 代码块(静态代码块,for等)

Pointcuts

AspectJ中的切面(这种翻译不一定正确),由点及面,用于说明你需要hook哪一类问题,比如我需要hook所有的Activity的生命周期方法,则:


@Pointcut("execution(* android.app.Activity.on*(..))")

advice

Join Points和Pointcuts用来说明需要hook哪些位置或者流程,advice则用于hook之后指定需要做什么,包括:

before() 在切入点之前操作

after() 在切入点之后操作

  • after():returning 函数正常结束

  • after():throwing 函数异常结束

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

  • "execution(* android.view.View.OnClickListener.onClick(..))"对应Pointcuts,即用一个类似正则表达式来告诉控制器你需要hook哪些函数(方法)

  • execution:表示hook的流程是函数执行过程(Join Points有很多种,execution只是其中一种,具体可参见AspectJ官方文档)
     android.view.View.OnClickListener.onClick(..)) :表示android.view.View.OnClickListener该类(或接口)下的所有名为onClick,参数个数未知,参数类型未知的函数

总结

我们通过面向切面思想来过滤掉了重复点击的事件,且高度解耦,可以看到代码非常简单,AOP重在理解这种思想且找准切入点;AOP在Android中还可以有非常多的应用,如:

  • Android API23+的权限控制

  • 无痕埋点

  • 全局是否登录流程控制

  • 路由控制

  • 日志系统

  • 事件防抖(重复点击)

  • ...

后面有机会再聊这些应用;文章如有任何描述不正确或欠妥的地方,还请大家务必提出来我及时改正,免得误导更多盆友;

参考:深入理解Android之AOP

来源:https://www.jianshu.com/p/483d6ae21322

标签:android,aop,过滤
0
投稿

猜你喜欢

  • SpringBoot集成kaptcha验证码

    2023-06-26 03:56:17
  • Java经典面试题最全汇总208道(三)

    2023-11-15 23:30:42
  • java JUC信号量Semaphore原理及使用介绍

    2023-01-02 02:08:57
  • Java泛型定义与用法实例详解

    2023-11-25 11:50:28
  • 浅谈Java slf4j日志简单理解

    2021-07-07 15:49:15
  • 详解Java中的Vector

    2023-06-05 01:40:49
  • Spring Boot项目实战之拦截器与过滤器

    2022-08-04 15:55:31
  • C# CSV文件读写的实现

    2023-05-24 10:39:07
  • Android编程中activity启动时出现白屏、黑屏问题的解决方法

    2023-03-09 06:15:03
  • 基于Spring AOP proxyTargetClass的行为表现总结

    2022-05-23 18:33:43
  • 详谈hibernate,jpa与spring data jpa三者之间的关系

    2022-08-04 22:35:57
  • Java编程实现向文本文件中读取数据之Scanner用法示例

    2022-08-01 03:38:57
  • Android实现双击返回键退出应用实现方法详解

    2023-03-23 21:33:29
  • springboot读取配置文件中的参数具体步骤

    2023-11-29 05:46:14
  • Mybatis注解实现多数据源读写分离详解

    2021-12-15 21:44:16
  • SpringBoot打Jar包在命令行运行流程详解

    2023-11-24 16:53:59
  • SpringBoot访问外部文件及默认路由问题

    2021-08-12 10:58:01
  • 解决idea每次新建项目都需要重新指定maven目录

    2022-12-25 17:39:52
  • C#之set与get方法的用法案例

    2021-08-09 01:17:18
  • Windows下安装ElasticSearch的方法(图文)

    2023-11-25 13:35:35
  • asp之家 软件编程 m.aspxhome.com