AOP(Aspect Oriented Programming),即面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP(Object Oriented Programming , 面向对象编程)的延续、补充。利用AOP可以对业务逻辑的各个模块或各个功能进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
这篇文章是接之前的一篇文章《安卓中利用注解生成java代码》
文章目录
为什么使用AOP
其实上面已经大概说了。大家都知道java是面向对象编程的高级语言,面向对象的编程可以使代码模块化、高内聚低耦合,从而方便功能拓展和代码维护,降低开发成本,提高代码质量,甚至提升产品的稳定性。
但是实际的项目开发中必然涉及到一些穿插在各个模块的重复功能,这个功能本身我们可以直接模块化,但是这个功能模块需要在各个其它模块的地方使用,必然会使其它模块产生依赖,影响模块的独立性,比如:安卓权限检测、网络检测、日志输出等。当然不是说模块间调用不可以,只是从开发者角度,这是可以有优化空间的,这个时候就需要面向切面的编程方法了。
AOP注解等知识
注解解释:
@Aspect:声明切面,用来标记类的,可以理解是横切面
@Pointcut(切点表达式):定义切点,标记方法的,切面上的具体的切点
//下面的都是统一的切点处理类
@Before(切点表达式):前置通知,切点之前执行
@Around(切点表达式):环绕通知,切点前后执行
@After(切点表达式):后置通知,切点之后执行
@AfterReturning(切点表达式):返回通知,切点方法返回结果之后执行
@AfterThrowing(切点表达式):异常通知,切点抛出异常时执行
JointPoint一些方法(以本文的实例为例):
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String name = signature.getName(); // 方法名:click
Method method = signature.getMethod(); // 方法:click方法信息实体类
Class returnType = signature.getReturnType(); // click返回值类型
Class declaringType = signature.getDeclaringType(); // 方法所在类名:MainActivity
String[] parameterNames = signature.getParameterNames(); // 参数名:activity
Class[] parameterTypes = signature.getParameterTypes(); // 参数类型:Activity
Object[] args = signature.getArgs(); //click里的参数传的值,这里就是一个MainActivity的实体类
使用AOP权限检测实践
1,添加插件和使用(这里使用是apectj插件)
在project的build.gradle中添加:
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
在app的build.gradle中添加:
apply plugin: 'com.android.application'
apply plugin: 'android-aspectjx'
2,定义注解类和切面处理类
注解类如下:
/**
* 权限检测注解
* <p>
* <略>
*
* @author : liuxs
* @date : 2020/5/15
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)//注意:这里必须使用RetentionPolicy.RUNTIME,如果使用class或者source会在运行时注解消失不起作用
public @interface RequestPermission {
/**
* 需要申请的权限
*
* @return
*/
String[] permissions() default {};
}
切面处理类:
/**
* 权限切面处理类
* <p>
* <权限检测统一放这里处理,其它模块如果需要动态权限检测,直接使用注解{@link RequestPermission}>
*
* @author : liuxs
* @date : 2020/5/15
*/
@Aspect
public class PermissionAspect {
@Pointcut("execution(@com.gome.permissionsdemo.RequestPermission * *(..))")
public void checkPermissions(){
}
/**
* 这里除了@Around(表示包围了添加了注解的方法),还可以使用
*
* @see org.aspectj.lang.annotation.After 表示添加了注解的方法执行之后执行
* @see org.aspectj.lang.annotation.Before 表示添加了注解的方法执行之前执行
* @see org.aspectj.lang.annotation.AfterReturning 表示添加了注解的方法执行返回后执行
* @see org.aspectj.lang.annotation.AfterThrowing 表示添加了注解的方法执行有异常时执行
*
* @param proceedingJoinPoint
*/
@Around("checkPermissions()")
public void _checkPermissions(final ProceedingJoinPoint proceedingJoinPoint){
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
RequestPermission requestPermission = methodSignature.getMethod().getAnnotation(RequestPermission.class);
if(requestPermission == null){
return;
}
String[] permissions = requestPermission.permissions();
Object[] args = proceedingJoinPoint.getArgs();
if(args == null ||args.length == 0){
return;
}
Activity appCompatActivity = (Activity)args[0];
if(args[0] instanceof Activity){
EasyPermissions.checkPermissions(appCompatActivity, permissions, new PermissionsCallback() {
@Override
public void permissionsGranted() {
//TODO 授权后执行
try {
//执行被注解的方法
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
@Override
public void permissionsDenied() {
//TODO 权限拒绝后执行
}
});
}else{
}
}
}
3,其它模块使用
这里权限申请成功后Toast 获取权限成功
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.hellotv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
/*EasyPermissions.checkPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA , Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsCallback() {
@Override
public void permissionsGranted() {
//TODO 授权后执行
}
@Override
public void permissionsDenied() {
//TODO 权限拒绝后执行
}
});*/
click(MainActivity.this);
}
});
}
@RequestPermission(permissions={Manifest.permission.CAMERA , Manifest.permission.WRITE_EXTERNAL_STORAGE})
public void click(Activity activity) {
Toast.makeText(MainActivity.this,"获取权限成功",Toast.LENGTH_SHORT).show();
}
}
注意:
如果报zip、jar为空,检查一下切面处理类是否有问题,比如:execution拼写错误,写成了executation;execution后面的注解写错了;注解后面的“* *(…)”写错了,第一个(*)代表类,然后空格,然后*代表方法,(…)代表形参。
demo有需要的可以私信获取
又到周末了,世界那么大,人生有那么短,我想出去转转!