一般情况我们的App里面在各个界面会有判断是否登录,如果用户登录过了直接进行下一步操作,如用户没有登录则跳转到登录界面,或者在用户操作某一步时手机相关信息等,我们都可以使用AOP切面进行处理。
例如之前我们这么写:
if(isLogin) {
// 如果登录才跳转,进入我的关注页面
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
}else{
//跳转到登录页面,先登录
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
}
这样我们如果这样处理,代码量上会增加很多,不断的写着重复的代码,
现在我们这样写,通过AOP注解方式:
@UserInfoGet()
public void loginTo(View view) {
Log.d("UserInfoAspectJ"," ------loginTo----->执行登录呦" );
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
}
AspectJ
AspectJ实际上是对AOP编程思想的一个实践,AOP虽然是一种思想,但就好像OOP中的Java一样,一些先行者也开发了一套语言来支持AOP。目前用得比较火的就是AspectJ了,它是一种几乎和Java完全一样的语言,而且完全兼容Java(AspectJ应该就是一种扩展Java,但它不是像Groovy那样的拓展。)。当然,除了使用AspectJ特殊的语言外,AspectJ还支持原生的Java,只要加上对应的AspectJ注解就好。所以,使用AspectJ有两种方法:
- 完全使用AspectJ的语言。这语言一点也不难,和Java几乎一样,也能在AspectJ中调用Java的任何类库。AspectJ只是多了一些关键词罢了。
- 或者使用纯Java语言开发,然后使用AspectJ注解,简称@AspectJ。
基础概念
- Aspect 切面:切面是切入点和通知的集合。
PointCut 切入点:切入点是指那些通过使用一些特定的表达式过滤出来的想要切入Advice的连接点。
Advice 通知:通知是向切点中注入的代码实现方法。
Joint Point 连接点:所有的目标方法都是连接点.
使用:
首先是app的build.gradle增加以下内容:
先增加一个依赖包:
implementation 'org.aspectj:aspectjrt:1.9.4'
然后在增加下面的内容,下面的内容直接全部复制,然后粘贴到build.gradle最下面:
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
final def log = project.logger
final def variants = project.android.applicationVariants
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.9.4'
classpath 'org.aspectj:aspectjweaver:1.9.4'
}
}
//在构建工程时,执行编辑
variants.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.9",
"-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;
}
}
}
}
上面的直接放在你的build.gradle中最下面,不需要放在已有的大括号中,看一下:
然后编译,编译好了后会报一个提醒,不需要管它,然后接着写重要内容:
1、先写一个 BehaviorOne ,然后加上注解,
@Target(ElementType.METHOD) 是表示注解是在哪里起作用,这里是METHOD表示在方法上加注解
@Retention(RetentionPolicy.RUNTIME) 表示在运行时处理
写好之后是这样的:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BehaviorOne {
}
2、然后在定义一个类 UserInfoAspectJ:
import android.util.Log;
import com.wwy.mytestapp.apo.BehaviorOne;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
@Aspect
public class UserInfoAspectJ {
boolean isLogin = false;
/**
* //找到处理的切入点
*/
@Pointcut("execution(@com.wwy.mytestapp.apo.BehaviorOne * *(..))")
public void methodWithBehavior(){
}
/**
* 处理切面
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("methodWithBehavior()")
public Object isLogin(ProceedingJoinPoint joinPoint) throws Throwable{
Log.e("UserInfoAspectJ"," : 进入切面====----===");
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
//根据方法名拿到注解
BehaviorOne behaviorOne = methodSignature.getMethod().getAnnotation(BehaviorOne.class);
// 判断当前用户是否登录
if (behaviorOne != null) {
if (!isLogin) {
Log.e("UserInfoAspectJ", " : 未登录,请先登录。");
isLogin = true;
return null;
} else {
Log.e("UserInfoAspectJ", " : 已登录,-------》 ");
return joinPoint.proceed();
}
}
return joinPoint.proceed();
}
}
3、下面就是在activity中处理了,我这里简单的写了一个button登录按钮,
然后在activity中的点击方法是这样:
@BehaviorOne()
public void loginTo(View view) {
Log.d("UserInfoAspectJ"," ------loginTo----->执行登录呦" );
}
然后当用户点击的登录按钮的时候,它不会立刻打印上面的 执行登录呦 ,而是先执行 UserInfoAspectJ 类,然后执行其中的 isLogin 方法 ,里面有进行判断处理。如果未登录会先打印:
Log.e("UserInfoAspectJ", " : 未登录,请先登录。");
若已登录,则直接执行点击事件里面的代码。
基本思路就是这些了。在此做个记录,下次好直接使用。