面向切面编程(AOP)在Android中的应用

2018-10-18 15:07:53 浏览数 (1)

看完本篇文章你将学到什么? 1.基本了解AOP的编程思想,以及如何在Android中使用AOP的思想 2.借助AspectJ用AOP的思想实现埋点逻辑 3.借助AspectJ用AOP的思想实现屏蔽快速点击事件的处理

什么是AOP

AOP,字面翻译为面向切面编程。它是一种编程思想,不是什么新技术。可以这么理解,在Android开发过程中,我们经常会在我们的具体业务代码中加入全局性、系统性的与具体业务无关的代码。比如埋点、动态申请权限等等。AOP的思想就是将这些与业务无关的系统性的功能解耦出来,让代码看起来更清晰一点。使用AOP思想与正常程序流程的对比我们可以通过下面示例图片有个基础的认识:

上图1我们看到是我们正常的程序流程,程序的执行就像水从管道流出一样从上到下顺畅的纵向执行。图2为我们展示了AOP思想的程序执行流程,从图中可以看到我们的管道被从某一点横向的切开(AOP中将这个切点定义为pointCut),然后会在切入点植入一段我们在Aspect(类似于Java的类的理念,AOP中用来管理切点和执行代码块的一个概念)中定义的代码。示例仅是一种演示,实际情况是植入执行的代码块可以向被插入方法的前后同时植入代码块。目前实现AOP思想的框架有AspectJ、Spring、JBoss4.0等等。

AspectJ框架

为什么这里选择介绍AspectJ呢?主要是我公司的项目使用的是这个框架。那么什么是AspectJ?

它是实现AOP思想的一个框架,拥有自己的编译器和语法,可以在编译期间将需要植入的代码编译成Java代码插入到你的源代码文件当中。更直白点

我们的Android项目引用也非常的简单,2步就可以搞定:

  • 在项目的根目录的Build.gradle文件中加入下面的代码: 1dependencies { 2 classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0' 3}
  • 在你的app模块或者其他module中添加依赖: 1dependencies { 2 implementation 'org.aspectj:aspectjrt:1.8.9' 3}

应用

我们在项目中经常会遇到一个小问题,就是你对一个View绑定的一个点击事件用户疯狂的快速点击导致点击事件的处理代码被重复执行,常见的处理方式就是在点击事件中加入时间判断的逻辑,在短时间内的重复点击不做响应。但是如果有很多点击事件,这样处理起来显然让代码不好看。

所以,借助AspectJ中的AOP思想,可以在解决快速重复点击的问题的同时,可以让你的代码看的更优雅一点。

第一步:自定义一个注解
代码语言:javascript复制
1@Retention(RetentionPolicy.RUNTIME)
2@Target(ElementType.METHOD)
3public @interface IgnoreFastClick {
4    long value() default 2000;
5}
第二步:写Aspect植入的类
代码语言:javascript复制
 1@Aspect
 2public class IgnoreFastClickAspect {
 3
 4    int lastViewId=-1;
 5    long lastClickTime=0;
 6
 7    @Pointcut("execution(@com.bob.www.testdemo.aop.IgnoreFastClick * *(..))")
 8    public void hhh(){
 9    }
10
11    @Around("hhh()")
12    public void insertCodeBlock(ProceedingJoinPoint joinPoint) throws Throwable {
13        View view;
14        //取click方法中的参数view
15        if (joinPoint.getArgs() != null
16                && joinPoint.getArgs().length > 0
17                && joinPoint.getArgs()[0] instanceof View) {
18            view = ((View) joinPoint.getArgs()[0]);
19            if (view == null)
20                return;
21        } else {
22            return;
23        }
24
25        MethodSignature methodSignature = ((MethodSignature) joinPoint.getSignature());
26        Method method = methodSignature.getMethod();
27        if (method.isAnnotationPresent(IgnoreFastClick.class)) {
28            IgnoreFastClick ignoreFastClick = method.getAnnotation(IgnoreFastClick.class);
29            long nowTime = System.currentTimeMillis();
30            // 如果两次点击时间差小于或等于value的值,并且两次点击的是同一个View,就不执行onClick()方法
31            if (nowTime - lastClickTime <= ignoreFastClick.value()
32                    && view.getId() == lastViewId) {
33                Log.d("AOP", "you click is too fast!");
34            } else {
35                // 记住上一次点击的时间戳和View的ID
36                lastViewId = view.getId();
37                lastClickTime = nowTime;
38                执行onCLick()方法
39                joinPoint.proceed();
40            }
41        }
42    }
43}
第三步:给click事件方法加注解
代码语言:javascript复制
 1    @Override
 2    protected void onCreate(Bundle savedInstanceState) {
 3        super.onCreate(savedInstanceState);
 4        setContentView(R.layout.activity_main);
 5
 6        mTestBtn = findViewById(R.id.btn_test);
 7        mTestBtn.setOnClickListener(new View.OnClickListener() {
 8
 9            @IgnoreFastClick
10            @Override
11            public void onClick(View v) {
12                Log.d("AOP", "----------------" number  );
13            }
14        });
15    }

以后只要做防重点击的事件,只用加个注解就搞定了。

要想完全掌握AspectJ的语法还是挺多的,这里只是一个简单的抛砖引玉的例子哦。读者可以试试使用AspectJ完成事件统计相关的逻辑哦。讲的不好,仅供参考。

如果觉得本文对你有一点点的帮助,关注一下又能有什么损失呢?

0 人点赞