Android上运用AOP的思想开发,可以快速的帮助我们简化在横向开发中的重复性工作,简单的说就是把涉及到众多模块的某一类问题进行统一管理比如:性能检测、日志打印手机等。
AspectJ实际上是对AOP编程思想的一个实践,当然,除了AspectJ以外,还有很多其它的AOP实现,例如ASMDex、javassist等,但目前最好、最方便的,依然是AspectJ。
直接贴例子
- 引入插件,这边是添加在app.gradle, 不是添加在项目的gradle中
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.1' //引入aspectj的classpath
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.2"
defaultConfig {
applicationId "m4399.aspectjdemo"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:26.+'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'org.aspectj:aspectjrt:1.8.1' //添加对应的依赖
}
final def log = project.logger
final def variants = project.android.applicationVariants
//在全局变量中配置编译项以及,对应的log输出
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;
}
}
}
}
- 编写注解
@Retention(RetentionPolicy.CLASS)
@Target({ ElementType.CONSTRUCTOR, ElementType.METHOD })
public @interface DebugTrace {
}
- 日志打印类
public class DebugLog {
private DebugLog() {}
/**
* Send a debug log message
*
* @param tag Source of a log message.
* @param message The message you would like logged.
*/
public static void log(String tag, String message) {
Log.d(tag, message);
}
}
- 方法耗时检测类
public class StopWatch {
private long startTime;
private long endTime;
private long elapsedTime;
public StopWatch() {
//empty
}
private void reset() {
startTime = 0;
endTime = 0;
elapsedTime = 0;
}
public void start() {
reset();
startTime = System.nanoTime();
}
public void stop() {
if (startTime != 0) {
endTime = System.nanoTime();
elapsedTime = endTime - startTime;
} else {
reset();
}
}
public long getTotalTimeMillis() {
return (elapsedTime != 0) ? TimeUnit.NANOSECONDS.toMillis(endTime - startTime) : 0;
}
}
- Aspect 类的开发
@Aspect
public class TraceAspect {
private static final String POINTCUT_METHOD =
"execution(@com.bao.aspectjdemo.DebugTrace * *(..))"; //对应着注解类的包名+类名
private static final String POINTCUT_CONSTRUCTOR =
"execution(@com.bao.aspectjdemo.DebugTrace *.new(..))";
@Pointcut(POINTCUT_METHOD)
public void methodAnnotatedWithDebugTrace() {}
@Pointcut(POINTCUT_CONSTRUCTOR)
public void constructorAnnotatedDebugTrace() {}
@Around("methodAnnotatedWithDebugTrace() || constructorAnnotatedDebugTrace()")
public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String className = methodSignature.getDeclaringType().getSimpleName();
String methodName = methodSignature.getName();
final StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object result = joinPoint.proceed();
stopWatch.stop();
DebugLog.log(className, buildLogMessage(methodName, stopWatch.getTotalTimeMillis()));
return result;
}
/**
* Create a log message.
*
* @param methodName A string with the method name.
* @param methodDuration Duration of the method in milliseconds.
* @return A string representing message.
*/
private static String buildLogMessage(String methodName, long methodDuration) {
StringBuilder message = new StringBuilder();
message.append("AspectJDemo --> ");
message.append(methodName);
message.append(" --> ");
message.append("[");
message.append(methodDuration);
message.append("ms");
message.append("]");
return message.toString();
}
}
- 调用
@DebugTrace
@Override
public void onClick(View v) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
以上是个人参考例子https://github.com/android10/Android-AOPExample 熟悉了一遍
补充:Android-AOPExample的例子下载下来,在gradle版本再2.3.0及其以上的版本编译会出现问题
报错误:No such property: project for class: com.android.build.gradle.LibraryPlugin
- 解决方法一:注释掉LibraryPlugin plugin = project.plugins.getPlugin(LibraryPlugin)
和 “-bootclasspath”, plugin.project.android.bootClasspath.join(File.pathSeparator) - 解决方法二:将plugin.project.android.bootClasspath.join(File.pathSeparator) 替换为 android.bootClasspath.join(File.pathSeparator)
参考文章: