在Android项目中使用AspectJ
版权声明:本文为博主原创文章,未经博主允许不得转载。
转载请表明出处:http://www.cnblogs.com/cavalier-/p/8888459.html
什么是AOP
AOP是 Aspect Oriented Programming 的缩写,即面向切面编程,和平常遇到的面向对象OOP编程不一样的是,OOP是将功能模块化对象化,AOP是针对同一类的问题统一化处理。例如做日志埋点,性能监控,动态权限控制等。
AspectJ
AspectJ实际上是对AOP编程的实践,目前还有很多的AOP实现,如ASMDex,但笔者选用的是AspectJ。
在Android项目中使用AspectJ
如果使用原生AspectJ在项目中配置会非常麻烦,在GitHub上有个开源的SDK gradle_plugin_android_aspectjx基于gradle配置即可。
接入说明
请自行查看开源项目中的接入配置过程
AspectJ 之 Join Points介绍
Join Points在AspectJ中是关键的概念。Join Points可以看做是程序运行时的一个执行点,比如:一个函数的调用可以看做是个Join Points,相当于代码切入点。但在AspectJ中,只有下面几种执行点是认为是Join Points:
Join Points | 说明 | 实例 |
---|---|---|
method call | 函数调用 | 比如调用Log.e(),这是一个个Join Point |
method execution | 函数执行 | 比如Log.e()的执行内部,是一处Join Points。注意这里是函数内部 |
constructor call | 构造函数调用 | 和method call 类似 |
constructor execution | 构造函数执行 | 和method execution 类似 |
field get | 获取某个变量 | 比如读取DemoActivity.debug成员 |
field set | 设置某个变量 | 比如设置DemoActivity.debug成员 |
pre-initialization | Object在构造函数中做的一些工作。 | - |
initialization | Object在构造函数中做的工作。 | - |
static initialization | 类初始化 | 比如类的static{} |
handler | 异常处理 | 比如try catch 中,对应catch内的执行 |
advice execution | 这个是AspectJ 的内容 | - |
Pointcuts 介绍
一个程序会有多个Join Points,即使同一个函数,也还分为call 和 execution 类型的Join Points,但并不是所有的Join Points 都是我们关心的,Pointcuts 就是提供一种使得开发者能够值选择所需的JoinPoints的方法。
Advice
Advice就是我们插入的代码可以以何种方式插入,有Before 还有 After、Around。
下面看个例子:
@Before(“execution(* android.app.Activity.on**(..)))”)
public void onActivityMethodBefore(JoinPoint joinPoint) throws Throwable{
}
这里会分成好几个部分,我们依次来看:
- @Before: Advice, 也就是具体的插入点
- execution:处理Join Point的类型,例如call、execution
(* android.app.Activity.on**(..))
: 这个是最重要的表达式,第一个*
表示返回值,*
表示返回值为任意类型,后面这个就是典型的包名路径,其中可以包含*
来进行通配,几个*
没有区别。同时这里可以通过&&、||、!
来进行条件组合。()代表这个方法的参数,你可以指定类型,例如android.os.Bundle,或者 (..) 这样来代表任意类型、任意个数的参数。- public void onActivityMehodBefore: 实际切入的代码。
Before 和 After 其实还是很好理解的,也就是在Pointcuts之前和之后,插入代码,那么Android呢,从字面含义上来讲,也就是在方法前后各插入代码,他包含了 Before和 After 的全部功能,代码如下:
@(“execution(* com.xys.aspectjxdemo.MainActivity.testAOP()))”)
public void onActivityMethodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{String key = proceedingJoinPoint.getSignature().toString();Log.d(TAG,”onActivityMethodAroundFirst:”+key);proceedingJoinPoint.proceed();Log.d(TAG,”onActivityMethodAroundSecond:”+key);
}
以上代码中,proceedingJoinPoint.proceed()代表执行原始的方法,在这之前、之后,都可以进行各种逻辑处理。
自定义Pointcuts
自定义Pointcuts可以让我们更加精准的切入一个或多个指定的切入点。
首先我们要定义一个注解类
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface DebugTrace {
}
在需要插入代码的地方加入这个注解,例如在MainActivity中加入:
public class MainActivity extends AppCompatActivity{final String TAG = MainActivity.class.getSimpleName();@Overrideprotedcted void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);logTest();}@DebugTracepublic void logTest(){Log.e(TAG,”log test");}
}
最后创建切入代码
@Pointcut(“execution(@com.kun.aspectjtest.aspect.DebugTrace * *..*.*(..))”)
public void DebugTraceMethod(){}@Before(“DebugTraceMethod()”)
public void beforeDebugTraceMethod(JoinPoint joinPoint) throws Throwable{String key = joinPoint.getSignature().toString();Log.e(TAG, “beforeDebugTraceMethod:”+key);
}
Call
在AspectJ的切入点表达式中,我们前面都是使用的execution,实际上还有一种类型—call,那么这两种语法有什么区别呢?对call来说:
Call (Before)
Pointcut{Pointcut Method
}
Call (After)
对Execution来说:
Pointcut{execution (Before)Pointcut Methodexecution (After)
}
Withincode
这个语法通常来进行一些切入点条件的过滤,作更加精确的切入控制,如下:
public class MainActivity extends AppCompatActivity{final String TAG = MainActivity.class.getSimpleName();@Orverideprotected void onCreate(Bundle savedInstanceState){super.onCreate(saveInstanceState);setContentView(R.layout.activity_main);aspectJ1();aspectJ2();aspectJ3();}public void aspectJTest(){Log.e(TAG,”execute aspectJTest");}public void aspectJ1(){aspectJTest();}public void aspectJ2(){aspectJTest();}public void aspectJ3(){aspectJTest();}
}
aspectJ1(),aspectJ2(),aspectJ3()都调用了aspectJTest方法,但只想在aspectJ2调用aspectJTest时插入代码,这个时候就需要使用到Pointcut和withcode组合的方式,来精确定位切入点。
@Pointcut(“(call(* *..aspectJTest()))&&withincode(* *..aspectJ2())”)
public void invokeAspectJTestInAspectJ2(){
}@Before(“invokeAspectJTestInAspectJ2()”)
public void beforeInvokeaspectJTestInAspectJ2(JoinPoint joinPoint) throws Throwable{Log.e(TAG,”method:”+getMethodName(joinPoint).getName());
}private MethodSignature getMethodName(JoinPoint joinPoint){if(joinPoint == null) return null;return (MethodSignature) joinPoint.getSignature();
}
execution 语法
execution()是最常用的切点函数,其语法如下所示:
例如下面这段语法:
@Around(“execution(* *..MainActivity+.on*(..))")
整个表达式可以分为五个部分:
- execution()是表达式主体
- 第一个
*
号代表返回类型,*号代表所有的类型。 - 包名 表示需要拦截的包名,这里使用*.代表匹配所有的包名。
- 第二个*号表示类名,后面跟.MainActivity是指具体的类名叫MainActivity。
*(..)
最后这个星号表示方法名,+.代表具体的函数名,*
号通配符,包括括弧号里面表示方法的参数,两个dot代表任意参数。
遇到的错误
- 以下错误可以使用gradle2.2.3解决,由于目前还不适配gradle3.0导致的
Error:Execution failed for task ':app:transformClassesWithDexBuilderForDebug'.
> Unexpected scopes found in folder '/Users/ram/WorkSpace/AndroidWorkSpace/MyDemo/app/build/intermediates/transforms/AspectTransform/debug'. Required: PROJECT, SUB_PROJECTS, EXTERNAL_LIBRARIES. Found: EXTERNAL_LIBRARIES, PROJECT, PROJECT_LOCAL_DEPS, SUB_PROJECTS, SUB_PROJECTS_LOCAL_DEPS
转载于:https://www.cnblogs.com/cavalier-/p/8888459.html
在Android项目中使用AspectJ相关推荐
- android aspectj 参数,在Android项目中使用AspectJ
什么是AOP AOP是 Aspect Oriented Programming 的缩写,即面向切面编程,和日常遇到的面向对象OOP编程不同的是,OOP是将功能模块化对象化,AOP是针对同一类的问题统一 ...
- android使用webview上传文件,Android项目中如何在webview页面中上传文件
Android项目中如何在webview页面中上传文件 发布时间:2020-11-26 15:56:27 来源:亿速云 阅读:68 作者:Leah 本篇文章为大家展示了Android项目中如何在web ...
- Android项目中创建编译期的注解
==注解 生命周期为RetentionPolicy.RUNTIME,可在运行时通过反射获取. 生命周期为RetentionPolicy.CLASS, 编译期处理的注解,可以使用APT(Annotati ...
- Android项目中出现的Plugin with id ‘kotlin-android‘ not found解决方法
Android项目中出现的Plugin with id 'kotlin-android' not found解决方法 参考文章: (1)Android项目中出现的Plugin with id 'kot ...
- flutter打开android界面,在已有Android项目中使用Flutter
实现效果,在已存在的android项目中接入flutter,即android调用开启flutter页面(使用android打开flutter的指定页面),flutter调用原生android方法 步骤 ...
- XamarinSQLite教程在Xamarin.Android项目中提取数据库文件
XamarinSQLite教程在Xamarin.Android项目中提取数据库文件 由于不能直接打开该文件,开发者需要先将数据库文件从Android系统中提取出来.操作步骤如下. (5)选择MyDoc ...
- XamarinSQLite教程在Xamarin.Android项目中定位数据库文件
XamarinSQLite教程在Xamarin.Android项目中定位数据库文件 实际开发中,经常需要验证数据库操作的正确性.这个时候,需要打开数据库文件,进行确认.下面是如何找到MyDocumen ...
- XamarinSQLite教程在Xamarin.Android项目中使用数据库
XamarinSQLite教程在Xamarin.Android项目中使用数据库 在Xamarin.Android项目中使用预设数据库的具体操作步骤如下: (1)创建一个Xamarin.Android项 ...
- android项目中导入opencv库,将第二个JNI库包含到我的Android项目(OpenCV)后...
我试图将OpenCV添加到我现有的Android项目中,但是在合并它们时遇到了以下错误: 12-08 16:15:21.951 22052-22052/ai.inbi.face_recognition ...
最新文章
- 在text html模版中写js,Rails3使用text/html内容类型而不是text/javascript呈现js.erb模板...
- 如何用两个开关控制同一盏灯
- 大数据下union all的视图分页解决方案
- MFC日志(2011.4.9)
- SQL Server应用程序中的高级SQL注入
- [转载] 机器学习 - 如何使用 Java 调取 Python、R 的训练模型?
- Ubuntu 11.10为何值得我们期待?
- oracle 模拟阻塞,Oracle 阻塞(blocking blocked)介绍和实例演示
- 【MFC开发(6)】复选框按钮控件Check Box
- Sql面试50题 详解 持续更新
- 英语演讲和英语课件ppt模板
- CoreIDRAW出现“尝试重新启动计算机和应用程序...”问题解决方案
- 武汉星起航跨境:跨境电商新蓝海,南非跨境电商市场迸发活力
- 计算机字体安装按钮灰色,解决方案:在win10系统上将字体的安装按钮显示为灰色的详细步骤...
- latex中 号什么含义?
- 微软近日更新网页版Skype增通知版面和关键词搜寻
- 日本处方药【治疗肠癌】
- 计算机专业平均年龄,平均年龄27.07岁 去年23万人才“涌入”深圳
- UVM实战windows下运行
- DX9光照效果-------VB6编程学习DX9游戏编程DirectX9编程2D小游戏源码冷风引擎CoolWind2D游戏引擎(12)
热门文章
- css3 transform实现水平和垂直居中
- git中文件的三种状态
- [ACM训练] ACM中巧用文件的输入输出来改写acm程序的输入输出 + ACM中八大输入输出格式...
- ERP开发中应用字符串解析实现界面翻译智能化
- java corepoolsize_理解ThreadPoolExecutor线程池的corePoolSize、maximumPoolSize和poolSize
- springboot springcloud区别_SpringBoot回顾、Spring Cloud初学
- tcpdump 抓二层包_可能是我见过的最简单易懂且实用的 TCPDump 和 Wireshark 抓包及分析教程!( 强烈建议收藏 )...
- AUTOSAR从入门到精通-AUTOSAR PPT介绍
- 树莓派退出python的代码_Python实现树莓派WiFi断线自动重连的实例代码
- C语言输出最后一个空格去掉,新人提问:如何将输出时每行最后一个空格删除...