Table of Contents
AOP框架AspectJ的使用(Android)
一、什么是AOP
AOP是Aspect Oriented Programming的缩写,即『面向切面编程』。它和我们平时接触到的OOP都是编程的不同思想,OOP,即『面向对象编程』,它提倡的是将功能模块化,对象化,而AOP的思想,则不太一样,它提倡的是针对同一类问题的统一处理,当然,我们在实际编程过程中,不可能单纯的安装AOP或者OOP的思想来编程,很多时候,可能会混合多种编程思想,大家也不必要纠结该使用哪种思想,取百家之长,才是正道。
那么AOP这种编程思想有什么用呢,一般来说,主要用于不想侵入原有代码的场景中,例如SDK需要无侵入的在宿主中插入一些代码,做日志埋点、性能监控、动态权限控制、甚至是代码调试等等。
二、AspectJ
AspectJ实际上是对AOP编程思想的一个实践,当然,除了AspectJ以外,还有很多其它的AOP实现,例如ASMDex
三、在Android项目中使用AspectJ
3.1 配置AspectJ
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.9'
classpath 'org.aspectj:aspectjweaver:1.8.9'
}
}
apply plugin: 'com.android.application'
repositories {
mavenCentral()
}
final def log = project.logger
final def variants = project.android.applicationVariants
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.8",
"-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;
}
}
}
}
dependencies {
compile 'org.aspectj:aspectjrt:1.8.11'
}
3.2 自定义注解
package com.example.administrator.dn_02_aop;
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.CLASS)
public @interface BehaviorTrace {
String value();
int type();
}
3.3 用@Aspect标注切面
package com.example.administrator.dn_02_aop;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 切面
*/
@Aspect
public class BehaviorAspect
3.4 在切面类中定义PointCut(切入点)
/**
* 切点
*/
@Pointcut("execution(@com.example.administrator.dn_02_aop.BehaviorTrace * *(..))")
public void annoBehavior()
{
}
3.5 在切面类中定义Advance(通知)
/**
* @param point
* @return
* @throws Throwable
*/
@Around("annoBehavior()")
public Object dealPoint(ProceedingJoinPoint point) throws Throwable
{
//获取注入参数值
MethodSignature methodSignature= (MethodSignature) point.getSignature();
BehaviorTrace behaviorTrace=methodSignature.getMethod().getAnnotation(BehaviorTrace.class);
String type=behaviorTrace.value();
int value=behaviorTrace.type();
//获取方法名
String methodName = point.getSignature().toString();
//获取参数
Object[] objs = point.getArgs();
int i = ((View)objs[0]).getId();
boolean isEquals = i==R.id.btn1;
//打印注入参数,打印方法名
Log.i(TAG,"type="+type+";value="+value);
Log.i(TAG,"methodName="+methodName);
//打印方法参数是否为Button1
Log.i(TAG,"isEquals="+isEquals);
Log.i(TAG,"param type="+((View)objs[0]).getClass().getName());
//打印获取到的对象的方法
if(point.getThis() instanceof MainActivity)
{
Log.i(TAG,"count="+((MainActivity)(point.getThis())).getCount());
}
//打印日志开始时间
Log.i(TAG,";开始时间:"+simpleDateFormat.format(new Date()));
Log.i(TAG,"");
long beagin=System.currentTimeMillis();
//方法执行时
Object object=null;
try {
object=point.proceed();
}catch (Exception e)
{
}
//打印消耗时间
Log.i(TAG,"消耗时间: "+(System.currentTimeMillis()-beagin)+"ms");
return object;
}
3.6 对方法使用该注解
3.6.1 对click方法标注
/**
* 语音的模块
*
* @param view
*/
@BehaviorTrace(value = Utils.STR_TEXT1,type = Utils.MSG1)
public void doAudio(View view)
{
SystemClock.sleep(3000);
Log.i(TAG,"audio module");
}
3.6.2 内部类方法的标注
btn.setOnClickListener(new View.OnClickListener() {
@BehaviorTrace(value = "onClick1",type = Utils.MSG1)
@Override
public void onClick(View v) {
Log.i(TAG," 3333333");
}
});
3.6.3 对同一个方法多个按钮处理的标注
@BehaviorTrace(value ="",type = Utils.MSG1)
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn1:
Log.v(TAG,"onClick id="+R.id.btn1);
break;
case R.id.btn2:
break;
}
}