我的博客java
http://www.milovetingting.cnandroid
AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程,經過預編譯方式和運行期間動態代理實現程序功能的統一維護的一種技術。git
以上關於AOP的定義引用自百度百科。github
日誌記錄、性能統計、權限控制、埋點等編程
AOP的具體實現方案有不少,這裏選用AspectJ來簡單實現app
- 監聽View的點擊、頁面打開、關閉
- 爲方法添加開始、結束的日誌
- 統計方法運行時間
這裏引用AspectJX,AspectJX是基於AspectJ的一個AOP框架框架
新建Android工程,在項目根目錄下的build.gradle文件中添加依賴ide
dependencies { //... classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8' //... }
新建Module,類型選擇Android Library,在新建的library的build.gradle文件中,添加相應的依賴性能
apply plugin: 'android-aspectjx'
在app的build.gradle文件中增長對剛纔新建的library的引用及AspectJ的依賴gradle
apply plugin: 'android-aspectjx' dependencies { //... androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' }
在library中新建回調接口TrackCallBack
public interface TrackCallBack { /** * 當View被點擊 * * @param pageName * @param viewIdName */ void onClick(String pageName, String viewIdName); /** * 當頁面打開時 * * @param pageName */ void onPageOpen(String pageName); /** * 當頁面關閉時 * * @param pageName */ void onPageClose(String pageName); }
在library中新建切入點TrackPoint
public class TrackPoint { private static TrackCallBack mTrackCallBack; private TrackPoint() { } /** * 初始化 * @param trackCallBack */ public static void init(TrackCallBack trackCallBack) { mTrackCallBack = trackCallBack; } static void onClick(String pageName, String viewIdName) { if (mTrackCallBack == null) { return; } mTrackCallBack.onClick(pageName, viewIdName); } static void onPageOpen(String pageName) { if (mTrackCallBack == null) { return; } mTrackCallBack.onPageOpen(pageName); } static void onPageClose(String pageName) { if (mTrackCallBack == null) { return; } mTrackCallBack.onPageClose(pageName); } }
在library中新建切面TraceAspect
@Aspect public class TraceAspect { private static final String TAG = TraceAspect.class.getSimpleName(); @Pointcut("execution(* onClick(..))") public void onClickPointcut() { } @Pointcut("execution(* android.app.Activity+.onCreate(..))") public void activityOnCreatePointcut() { } @Pointcut("execution(* android.app.Activity+.onDestroy(..))") public void activityDestroyPointcut() { } @Around("onClickPointcut()") public void onClick(ProceedingJoinPoint joinPoint) throws Throwable { Object target = joinPoint.getTarget(); String className = ""; if (target != null) { className = target.getClass().getName(); } Object[] args = joinPoint.getArgs(); if (args.length > 0 && args[0] instanceof View) { View view = (View) args[0]; String entryName = view.getResources().getResourceEntryName(view.getId()); TrackPoint.onClick(className, entryName); } joinPoint.proceed(); } @Around("activityOnCreatePointcut()") public void pageOpen(ProceedingJoinPoint joinPoint) throws Throwable { Object target = joinPoint.getTarget(); String className = target.getClass().getName(); TrackPoint.onPageOpen(className); joinPoint.proceed(); } @Around("activityDestroyPointcut()") public void pageClose(ProceedingJoinPoint joinPoint) throws Throwable { Object target = joinPoint.getTarget(); String className = target.getClass().getName(); TrackPoint.onPageClose(className); joinPoint.proceed(); } }
在app模塊新建Application,在onCreate中執行初始化:
public class App extends Application { private static final String TAG = TraceAspect.class.getSimpleName(); @Override public void onCreate() { super.onCreate(); TrackPoint.init(new TrackCallBack() { @Override public void onClick(String pageName, String viewIdName) { Log.d(TAG, "onClick:" + pageName + "-" + viewIdName); //執行相應的業務 } @Override public void onPageOpen(String pageName) { Log.d(TAG, "onPageOpen:" + pageName); //執行相應的業務 } @Override public void onPageClose(String pageName) { Log.d(TAG, "onPageClose:" + pageName); //執行相應的業務 } }); } }
新增的Application須要在AndroidManifest中引用纔會生效。
運行App後,點擊打開另外一個Activity,而後依次退出Activity,輸出日誌以下:
2020-01-13 16:50:17.373 16610-16610/com.wangyz.aspectjdemo D/TraceAspect: onPageOpen:com.wangyz.aspectjdemo.MainActivity 2020-01-13 16:50:19.243 16610-16610/com.wangyz.aspectjdemo D/TraceAspect: onClick:com.wangyz.aspectjdemo.MainActivity-btn_open 2020-01-13 16:50:19.298 16610-16610/com.wangyz.aspectjdemo D/TraceAspect: onPageOpen:com.wangyz.aspectjdemo.SecondActivity 2020-01-13 16:50:21.392 16610-16610/com.wangyz.aspectjdemo D/TraceAspect: onPageClose:com.wangyz.aspectjdemo.SecondActivity 2020-01-13 16:50:22.320 16610-16610/com.wangyz.aspectjdemo D/TraceAspect: onPageClose:com.wangyz.aspectjdemo.MainActivity
在library中增長註解AddLog
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AddLog { }
在TraceAspect增長如下代碼
@Pointcut("execution(@com.wangyz.library.AddLog * *(..))") public void addLogPointcut() { } @Around("addLogPointcut()") public void addLog(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); AddLog addLog = signature.getMethod().getAnnotation(AddLog.class); if (addLog != null) { Object target = joinPoint.getTarget(); String className = ""; if (target != null) { className = target.getClass().getName(); } Log.d(TAG, "start execute:" + className + "-" + signature.getMethod().getName()); joinPoint.proceed(); Log.d(TAG, "end execute:" + className + "-" + signature.getMethod().getName()); } else { joinPoint.proceed(); } }
在MainActivity的onCreate上增長AddLog註解
@AddLog @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //... }
運行App後,輸入日誌以下:
2020-01-13 16:50:17.373 16610-16610/com.wangyz.aspectjdemo D/TraceAspect: start execute:com.wangyz.aspectjdemo.MainActivity-onCreate 2020-01-13 16:50:17.392 16610-16610/com.wangyz.aspectjdemo D/TraceAspect: end execute:com.wangyz.aspectjdemo.MainActivity-onCreate
在library中增長註解ExecTime
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ExecTime { }
在TraceAspect增長如下代碼
@Pointcut("execution(@com.wangyz.library.ExecTime * *(..))") public void execTimePointcut() { } @Around("execTimePointcut()") public void execTime(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); ExecTime execTime = signature.getMethod().getAnnotation(ExecTime.class); if (execTime != null) { long start = System.currentTimeMillis(); joinPoint.proceed(); long end = System.currentTimeMillis(); Object target = joinPoint.getTarget(); String className = ""; if (target != null) { className = target.getClass().getName(); } Log.d(TAG, "execute time:" + className + "-" + signature.getMethod().getName() + " : " + (end - start) + "ms"); } else { joinPoint.proceed(); } }
在onClick方法上增長ExecTime註解
@ExecTime @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_open: Intent intent = new Intent(this, SecondActivity.class); startActivity(intent); break; default: break; } }
運行App後,輸出日誌以下:
2020-01-13 16:50:19.272 16610-16610/com.wangyz.aspectjdemo D/TraceAspect: execute time:com.wangyz.aspectjdemo.MainActivity-onClick : 28ms
源碼地址:https://github.com/milovetingting/Samples/tree/master/AspectJDemo