做一个学习记录:
Android中的AOP编程
Android之AOP
Android Studio 中自定义 Gradle 插件
看AspectJ在Android中的强势插入
jarryleo / MagicBuriedPoint
AspectJ 的两种用法
(1)用自定义注解修饰切入点,精确控制切入点,属于侵入式;
(2)不需要在切入点代码中做任何修改,属于非侵入式。
侵入式
侵入式用法,一般会使用自定义注解,以此作为选择切入点的规则。
非侵入式
非侵入式,就是不需要使用额外的注解来修饰切入点,不用修改切入点的代码。
项目接入使用:
一般情况下我们会新建一个独立模块提供给其它项目接入使用,如下图TrackPoint模块
build.gradle模块配置
两种方式:1.apply plugin: 'android-aspectjx'
2.implementation 'org.aspectj:aspectjrt:1.8.+'
注解方式:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectAnalyze {
String name();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectDebugLog {
}
public class MainActivity extends Activity {
private Button myButton;
private final String TAG= this.getClass().getSimpleName();
@AspectAnalyze(name = "MainActivity.onCreate")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButton=findViewById(R.id.myButton);
myButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"text",Toast.LENGTH_LONG).show();
onNameClick();
}
});
}
@AspectDebugLog
@AspectAnalyze(name = "onNameClick")
public void onNameClick() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@AspectAnalyze(name = "MainActivity.onDestroy")
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
}
}
package com.trackpoint;
import android.util.Log;
import com.trackpoint.annotation.AspectAnalyze;
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;
import org.aspectj.lang.reflect.SourceLocation;
@Aspect
public class AnnotationAspectTrace {
private final String TAG = this.getClass().getSimpleName();
private static AspectTraceListener aspectTraceListener;
/**
* 针对所有继承 Activity 类的 onCreate 方法
*/
@Pointcut("execution(* android.app.Activity+.onCreate(..))")
public void activityOnCreatePointcut() {
}
/**
* 针对带有AspectAnalyze注解的方法
*/
@Pointcut("execution(@com.trackpoint.annotation.AspectAnalyze * *(..))")
public void aspectAnalyzeAnnotation() {
}
/**
* 针对带有AspectAnalyze注解的方法
*/
@Pointcut("execution(@com.trackpoint.annotation.AspectDebugLog * *(..))")
public void aspectDebugLogAnnotation() {
}
/**
* 针对前面 aspectAnalyzeAnnotation() 的配置
*/
@Around("aspectAnalyzeAnnotation()")
public void aroundJoinAspectAnalyze(final ProceedingJoinPoint joinPoint) throws Throwable {
Object target = joinPoint.getTarget();
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
AspectAnalyze aspectAnalyze = methodSignature.getMethod().getAnnotation(AspectAnalyze.class);
long startTimeMillis = System.currentTimeMillis();
joinPoint.proceed();
if (aspectTraceListener != null) {
aspectTraceListener.onAspectAnalyze(joinPoint, aspectAnalyze, methodSignature, System.currentTimeMillis() - startTimeMillis);
}
}
/**
* 针对前面 aspectDebugLogAnnotation() 或 activityOnCreatePointcut() 的配置
*/
@Around("aspectDebugLogAnnotation() || activityOnCreatePointcut()")
public void aroundJoinAspectDebugLog(final ProceedingJoinPoint joinPoint) throws Throwable {
long startTimeMillis = System.currentTimeMillis();
joinPoint.proceed();
long duration = System.currentTimeMillis() - startTimeMillis;
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
SourceLocation location = joinPoint.getSourceLocation();
String message = String.format("%s(%s:%s) [%sms]", methodSignature.getMethod().getName(), location.getFileName(), location.getLine(), duration);
if (aspectTraceListener != null) {
aspectTraceListener.logger("AspectTrace", message);
} else {
Log.e("AspectTrace", message);
}
}
public static void setAspectTraceListener(AspectTraceListener aspectTraceListener) {
AnnotationAspectTrace.aspectTraceListener = aspectTraceListener;
}
public interface AspectTraceListener {
void logger(String tag, String message);
void onAspectAnalyze(ProceedingJoinPoint joinPoint, AspectAnalyze aspectAnalyze, MethodSignature methodSignature, long duration);
}
}
非侵入式:
以下几个常用场景
package com.trackpoint;
import android.util.Log;
import android.widget.Toast;
import com.trackpoint.annotation.AspectAnalyze;
import org.aspectj.lang.JoinPoint;
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 org.aspectj.lang.reflect.SourceLocation;
@SuppressWarnings("unused")
@Aspect
public class AspectTrace {
private final String TAG = "AspectTrace";
@Around("call(* android.widget.Toast.setText(java.lang.CharSequence))")
public void handleToastText(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Log.d(TAG," start handleToastText");
proceedingJoinPoint.proceed(new Object[]{"处理过的toast"}); //这里把它的参数换了
Log.d(TAG," end handleToastText");
}
@Before("call(* android.widget.Toast.show())")
public void changeToast(JoinPoint joinPoint) throws Throwable {
Toast toast = (Toast) joinPoint.getTarget();
toast.setText("修改后的toast");
Log.d(TAG, " --> changeToast");
}
/**
* 在MainActivity的所有生命周期的方法中打印log
* @param joinPoint
* @throws Throwable
*/
@Before("execution(* android.app.Activity.**(..))")
public void method(JoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String className = joinPoint.getThis().getClass().getSimpleName();
Log.e(TAG, "class:" + className+" method:" + methodSignature.getName());
}
}
@Aspect
public class ViewAspect {
private final String TAG = "ViewAspect";
@Pointcut("execution(void android.view.View.OnClickListener.onClick(..))")
public void onClickPointcut() {
}
@Pointcut("execution(* *.*onTouch(..))")
public void onTouchPointcut() {
Log.d(TAG,"onTouchPointcut");
}
@Around("onClickPointcut()")
public void aroundJoinClickPoint(final ProceedingJoinPoint joinPoint) throws Throwable {
Object target = joinPoint.getTarget();
String className = "";
if (target != null) {
className = target.getClass().getName();
}
//获取点击事件view对象及名称,可以对不同按钮的点击事件进行统计
Object[] args = joinPoint.getArgs();
if (args.length >= 1 && args[0] instanceof View) {
View view = (View) args[0];
int id = view.getId();
String entryName = view.getResources().getResourceEntryName(id);
TrackPoint.onClick(className, entryName);
}
joinPoint.proceed();//执行原来的代码
}
}
遇到问题:
1.使用过程中经常对不上接口onTouch(..)
2.每次改变aspect代码需要clean项目
github demo代码:https://github.com/xingchongzhu/AspectJDemo