背景

Android 点击一个 View 跳到个页面这个常规事件,有时候用户会用他们单身几十年的手速1秒内戳了那么三四五六七八下,然后这个时候要是用户稍微手机性能差点,一下子就跳出那么两三个同样的 Activity 出来,这种去情况还是挺尴尬的,在这里我们可以用面向切面(AOP)的知识对我们这么一个重复事件进行拦截处理。

AspectJX

AspectJX 是个啥子东西来的?GitHub 上是这么说的

一个基于AspectJ并在此基础上扩展出来可应用于Android开发平台的AOP框架,可作用于java源码,class文件及jar包,同时支持kotlin的应用。

  • 插件引用
    在项目根目录的 build.gradle 里依赖 AspectJX
dependencies {     classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'}

在 app Module 的 build.gradle 里加入依赖

apply plugin: 'com.android.application'apply plugin: 'com.jakewharton.butterknife'apply plugin: 'android-aspectjx'//这一行 别加错地方了android {    ...}

好了 Sync 一下吧 ~
配置有问题就看一下官网吧亲~
顺道说一下我踩到的坑,AspectJX 和阿里推送以及某些推送 SDK 冲突问题。以下是我 Google 到的解决方法。

在当前的 module 的 gradle 文件加入如下

android {//.... 省略}dependencies {//.... 省略}//aspectj AOP 和 阿里推送的冲突问题import org.aspectj.bridge.IMessageimport org.aspectj.bridge.MessageHandlerimport org.aspectj.tools.ajc.Mainfinal def log = project.loggerfinal def variants = project.android.applicationVariantsvariants.all { variant ->    if (!variant.buildType.isDebuggable()) {        log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")        return;    }    JavaCompile javaCompile = variant.javaCompile    javaCompile.doLast {        String[] args = ["-showWeaveInfo",                         "-1.8",                         "-inpath", javaCompile.destinationDir.toString(),                         "-aspectpath", javaCompile.classpath.asPath,                         "-d", javaCompile.destinationDir.toString(),                         "-classpath", javaCompile.classpath.asPath,                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]        log.debug "ajc args: " + Arrays.toString(args)        MessageHandler handler = new MessageHandler(true);        new Main().run(args, handler);        for (IMessage message : handler.getMessages(null, true)) {            switch (message.getKind()) {                case IMessage.ABORT:                case IMessage.ERROR:                case IMessage.FAIL:                    log.error message.message, message.thrown                    break;                case IMessage.WARNING:                    log.warn message.message, message.thrown                    break;                case IMessage.INFO:                    log.info message.message, message.thrown                    break;                case IMessage.DEBUG:                    log.debug message.message, message.thrown                    break;            }        }    }}

拦截器

我们的拦截器要起到以下作用

  1. 在一定的时间内(可设置值)的重复点击事件的拦截,针对同一个 view
  2. 要求在某些情况下不需要拦截此点击事件(例如自定义view 的时候)

以下内容需要一点 AspectJX 和 AOP 的知识,如果无法理解建议先了解上面两个知识点。

首先写下我们的拦截事件

@Aspectpublic class InterceptAgainClickAOP {private final String TAG = this.getClass().getSimpleName();//上次点击的时间    private static Long sLastclick = 0L;    //拦截所有两次点击时间间隔小于一秒的点击事件    private static final Long FILTER_TIMEM = 1000L;    //上次点击事件View    private View lastView;        //拦截所有* android.view.View.OnClickListener.onClick(..) 事件    //直接setOnclikListener 拦截点击事件    @Around("execution(* android.view.View.OnClickListener.onClick(..))")    public void clickFilterHook(ProceedingJoinPoint joinPoint) throws Throwable {        //大于指定时间        if (System.currentTimeMillis() - sLastclick >= FILTER_TIMEM) {            doClick(joinPoint);        } else {            //小于指定秒数 但是不是同一个view 可以点击  或者不过滤点击            if (lastView == null || lastView != (joinPoint).getArgs()[0]) {                doClick(joinPoint);            } else {                //大于指定秒数 且是同一个view                Log.e(TAG, "重复点击,已过滤");            }        }    }        //执行原有的 onClick 方法    private void doClick(ProceedingJoinPoint joinPoint) throws Throwable {    //判断 view 是否存在        if (joinPoint.getArgs().length == 0) {            joinPoint.proceed();            return;        }        //记录点击的 view(最好加上捕获类型转换异常的try)        lastView = (View) (joinPoint).getArgs()[0];        //记录点击事件        sLastclick = System.currentTimeMillis();        //执行点击事件        try {            joinPoint.proceed();        } catch (Throwable throwable) {            throwable.printStackTrace();        }    }}

这个时候已经满足我们上述的第一个要求 : **在一定的时间内(可设置值)的重复点击事件的拦截,针对同一个 view **
接下来我们写一个注解

/** * 标记不需要拦截点击 * * @author Cassie * @date 2019年9月26日 */@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.TYPE}) public @interface UncheckClick {}

我们利用这个注解去标记不需要过滤的点击事件修改上面 InterceptAgainClickAOP.java 的代码

@Aspectpublic class InterceptAgainClickAOP {private final String TAG = this.getClass().getSimpleName();//上次点击的时间    private static Long sLastclick = 0L;    //拦截所有两次点击时间间隔小于一秒的点击事件    private static final Long FILTER_TIMEM = 1000L;    //上次点击事件View    private View lastView;    //---- add content -----//是否过滤点击 默认是    private boolean checkClick = true;    //---- add content -----        //拦截所有* android.view.View.OnClickListener.onClick(..) 事件    //直接setOnclikListener 拦截点击事件    @Around("execution(* android.view.View.OnClickListener.onClick(..))")    public void clickFilterHook(ProceedingJoinPoint joinPoint) throws Throwable {        //大于指定时间        if (System.currentTimeMillis() - sLastclick >= FILTER_TIMEM) {            doClick(joinPoint);        } else {        //---- update content -----  判断是否需要过滤点击            //小于指定秒数 但是不是同一个view 可以点击  或者不过滤点击            if (!checkClick ||lastView == null || lastView != (joinPoint).getArgs()[0]) {            //---- update content -----  判断是否需要过滤点击                doClick(joinPoint);            } else {                //大于指定秒数 且是同一个view                Log.e(TAG, "重复点击,已过滤");            }        }    }        //执行原有的 onClick 方法    private void doClick(ProceedingJoinPoint joinPoint) throws Throwable {    //判断 view 是否存在        if (joinPoint.getArgs().length == 0) {            joinPoint.proceed();            return;        }        //记录点击的 view        lastView = (View) (joinPoint).getArgs()[0];        //---- add content -----          //修改默认过滤点击        checkClick = true;        //---- add content -----          //记录点击事件        sLastclick = System.currentTimeMillis();        //执行点击事件        try {            joinPoint.proceed();        } catch (Throwable throwable) {            throwable.printStackTrace();        }    }        //标志不过滤点击    @Before("execution(@com.cassie.annotation.aop.UncheckClick * *(..))")    public void beforeuncheckClcik(JoinPoint joinPoint) throws Throwable {        Log.i(TAG, "beforeuncheckClcik");        //修改为不需要过滤点击        checkClick = false;    }}

以上就是整个过滤重复点击的 AOP 了,注释应该清楚了就不赘述啦~

更多相关文章

  1. autoMonkey框架原理与应用(一):Monkey基础知识与测试场景
  2. Android(安卓)可拖动可点击悬浮窗
  3. android使用篇(四) 注解依赖注入IOC实现绑定控件
  4. Android中对闹钟Alarm的事件处理
  5. android 自定义View(一) View的事件分发与绘制
  6. Android电子牌外接USB读卡器读取内容模拟键盘事件
  7. unity游戏开发 发布android 游戏 (一)
  8. 安装Android(安卓)studio的详细步骤
  9. 《Android开发艺术探索》之学习笔记(三)View的基础知识

随机推荐

  1. Kotlin让Android更简单~
  2. android网络编程——使用Android中的网络
  3. 启动app闪屏问题以及Android自带主题
  4. Android调用WCF
  5. Android滑动手势侦测方法介绍
  6. Android(安卓)中自定义View(三)
  7. Android(安卓)RelativeLayout 属性大全
  8. android 电容屏(一):电容屏基本原理篇
  9. android ndk 开发之 在 应用程序中使用 j
  10. Android(安卓)Studio:AndroidX的迁移