切面编程AOP在Android中该怎么使用

概念

大家一般开发中都是使用面向对象编程(OOP,即ObjectOriented Programming)但当你学习了切面编程(AOP,即Aspect Oriented Programming)后你会爱上这种编程,简直太好用了,不知道的人看了你的代码都还不知道这是怎么实现的。

面向切面编程:Aspect Oriented Programming(AOP),是目前软件百开发中的一个热点,也是Spring框架中的一个重要内容。 可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

优点:利用AOP可以对业务逻辑的各个部分进行隔离,从而使得度业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

配置即讲解

直接参考这篇文章:面向切面编程AspectJ在Android埋点的实践

配置好了后,我们看下面代码:

@Aspect
public class LifeCycleAspect {
    @Before("execution(* android.app.Activity.on**(..))")
    public void onActivityMethodBefore(JoinPoint joinPoint) {
        //方法名
        String methodName = joinPoint.getSignature().getName();
        //方法所在的类
        String target = joinPoint.getTarget().toString();
        Log.e("snow_aop", "类名:" + target + "=====方法名:" + methodName + "\n");
    }
    @After("execution(* *.my*(..))")
    public void onActivityMethodAfter(JoinPoint joinPoint) {

    }
    @Around("execution(* android.app.Activity.on**(..))")
    public void onActivityMethodAll(ProceedingJoinPoint joinPoint) {
        Log.e("snow_aop", "Around=======" + "onActivityMethodBefore:");
        try {
            //joinPoint.proceed()代表执行原始的方法
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        Log.e("snow_aop", "Around=======" + "onActivityMethodAfter:");
    }
}

上面代码就是一个aop切面编程代码,看代码有几点需要解释下:

1、@Aspect 在类名上需要注解代表此类是切面编程的类;
2、@Before:PointCut之前插入代码,先执行此代码逻辑;
@After:PointCut之后插入代码,执行代码结束在执行此代码逻辑;
@Around:Pointcuts之前和之后,插入代码,它包含了Before和After的全部功能;
注意:Around和After是不能同时作用在同一个方法上的,会产生重复切入的问题,导致切入失败。
3、“execution(* android.app.Activity.on**(…))”,关于它的说明直接看下图吧
在这里插入图片描述
4、onActivityMethodBefore等方法名是没有限制,想写什么方法就写什么方法
5、JoinPoint,这个可以获得很多被切入的方法信息,参考下面代码

 	@Before("execution(* *.my*(..))")
    public void onActivityMethodBefore(JoinPoint joinPoint) {
        //整体信息
        String key = joinPoint.getSignature().toString();
        //方法名
        String name = joinPoint.getSignature().getName();
        //方法所在的类
        String target = joinPoint.getTarget().toString();
        //方法在那个类多少行
        String s = joinPoint.getSourceLocation().toString();
        //方法中的参数,什么类型都可以,根据类型可以解析出参数的值
        Object[] args = joinPoint.getArgs();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                Object arg = args[i];
                if (arg instanceof UserBean) {
                    UserBean userBean = (UserBean) arg;
                    Log.e(TAG, "对象参数值:" + userBean.getName() + "===" + userBean.getAge() + "\n");
                } else {
                    String strinn = String.valueOf(arg);
                    Log.e(TAG, "参数值strinn:" + strinn + "\n");
                }
            }
        }

        Log.e(TAG, "onActivityMethodBefore:" + key + "\n" + joinPoint.getThis());
    }
    
	//被切入的方法
 	private boolean myPrivate(String mm) {
        return false;
    }
    public void myPublic(UserBean userBean) {
    }

使用

1、根据方法名进行切入

1、注入代码

@Aspect
public class TraceAspect {
    public static final String TAG = "snow_aop";
    /**
     * 在所有my开头的方法前执行
     *
     * @param joinPoint
     */
    @Before("execution(* *.my*(..))")
    public void onActivityMethodBefore(JoinPoint joinPoint) {
    	//方法名
        String name = joinPoint.getSignature().getName();
        //方法所在的类
        String target = joinPoint.getTarget().toString();
        //方法在那个类多少行
        String s = joinPoint.getSourceLocation().toString();
        //方法中的参数,什么类型都可以,根据类型可以解析出参数的值
        Object[] args = joinPoint.getArgs();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                Object arg = args[i];
                if (arg instanceof UserBean) {
                    UserBean userBean = (UserBean) arg;
                    Log.e(TAG, "对象参数值:" + userBean.getName() + "===" + userBean.getAge() + "\n");
                } else {
                    String strinn = String.valueOf(arg);
                    Log.e(TAG, "参数值strinn:" + strinn + "\n");
                }
            }
        }
        Log.e(TAG, "onActivityMethodBefore:" + key + "\n" + joinPoint.getThis());
    }
}

2、调用:你没看错,就是正常写法,没有任何调用,但你运行就会发现有数据打印出来了

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myPrivate("李四");
        myPublic(new UserBean("张三", 19));
        myNoParamsMethod();
    }
    private void myNoParamsMethod() {
    }
    private boolean myPrivate(String mm) {
        return false;
    }
    public void myPublic(UserBean userBean) {
    }

执行结果:
在这里插入图片描述

2、自定义注入,需要方法引用(依计算方法执行需要时间为例)

1、自定义注解类

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface DebugTimeConsuming {
}

2、自定义注解调用类

@Aspect
public class CustomAspect {
    /**
     * 注意此处DebugTimeConsuming是定义的注解类的路径
     */
    private static final String POINTCUT_METHOD =
            "execution(@com.snow.gintonic.custom.DebugTimeConsuming * *(..))";

    @Pointcut(POINTCUT_METHOD)
    public void methodAnnotatedWithDebugTrace() {
    }

    @Around("methodAnnotatedWithDebugTrace()")
    public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();
        String methodName = methodSignature.getName();
        UseTimeHelper useTimeHelper = new UseTimeHelper();
        //开始计时
        useTimeHelper.start();
        // 被注解的方法在这一行代码被执行
        Object result = joinPoint.proceed();
        //停止计时
        useTimeHelper.stop();
        //打印被监听方法的执行时间
        Log.e("snow_aop", className + " --> " + methodName + " --耗时--> " + useTimeHelper.getTotalTimeMillis() + "ms");
        return result;
    }
}

3、调用,在方法前添加@DebugTimeConsuming即可
在这里插入图片描述
执行结果:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值