「性能優(yōu)化1.0」啟動(dòng)分類及啟動(dòng)時(shí)間的測(cè)量
「性能優(yōu)化1.1」計(jì)算方法的執(zhí)行時(shí)間
一忽肛、計(jì)算方法的執(zhí)行時(shí)間
我們?cè)谇懊娴膸灼┛椭蟹治隽巳绾潍@取應(yīng)用的啟動(dòng)時(shí)間,我們也知道啟動(dòng)過程中我們能優(yōu)化的方向就是 Application 和 Activity 的生命周期擒权,那么我們現(xiàn)在就來計(jì)算在啟動(dòng)過程 Application 中每一個(gè)調(diào)用每一個(gè)方法的執(zhí)行耗時(shí)。
1.1、常規(guī)方案
手動(dòng)埋點(diǎn)的方式鸵隧,這種方案就是跟我們埋點(diǎn)獲取應(yīng)用啟動(dòng)時(shí)間是一樣的原理,只要在方法執(zhí)行前和執(zhí)行后埋點(diǎn)财破,然后計(jì)算這兩個(gè)埋點(diǎn)的時(shí)間差值就是該方法執(zhí)行的耗時(shí)時(shí)間了掰派。
具體的埋點(diǎn)實(shí)現(xiàn)如下代碼所示,在 Application 中 onCreate 方法中調(diào)用了很多初始化的方法左痢,我們通過埋點(diǎn)的方式在每一個(gè)調(diào)用的方法內(nèi)部都去計(jì)算其方法的耗時(shí)時(shí)間靡羡。
//Application.java
@Override
public void onCreate() {
initImageLoader();
initBugly();
initSharedPreference();
//.....
}
private void initImageLoader() {
long startTime = System.currentTimeMillis();
Fresco.initialize(this);
Log.d(TAG, "initImageLoader cost :" + (System.currentTimeMillis() - startTime));
private void initBugly() {
long startTime = System.currentTimeMillis();
//init bugly
Log.d(TAG, "initBugly cost :" + (System.currentTimeMillis() - startTime));
}
private void initSharedPreference() {
long startTime = System.currentTimeMillis();
//init SharedPreference
Log.d(TAG, "initSharedPreference cost :" + (System.currentTimeMillis() - startTime));
}
我們可以看到,以上這種方法是我們第一個(gè)想到的實(shí)現(xiàn)方式俊性,但是也是缺點(diǎn)也是很明顯:
- 代碼很不優(yōu)雅略步,每一個(gè)方法都需要進(jìn)行埋點(diǎn)。
- 對(duì)項(xiàng)目的侵入性很大定页,并且工作量也很大趟薄。
1.2、AOP方式來獲取
1.2.1典徊、基本概念
AOP 就是我們常說的面向切面編程
杭煎,它可以針對(duì)同一類問題
進(jìn)行統(tǒng)一處理
。
下面我們就來通過 AOP
的方式來優(yōu)雅的獲取Application
每一個(gè)方法的執(zhí)行時(shí)間卒落。
1.2.2羡铲、引入 AspectJ
在 Android 中通過 AspectJ 這個(gè)庫(kù)來使用 AOP ,接下來來引入這個(gè)庫(kù):
- 在工程根 build.gradle 中引入 AspectJ 插件
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
- 在 build.gradle 應(yīng)用插件
apply plugin: 'android-aspectjx'
- 在 build.gradle 中引入 aspectj 庫(kù)
implementation 'org.aspectj:aspectjrt:1.8.9'
好了通過以上幾步儡毕,我們就快速的接入的 AspectJ 這個(gè)庫(kù)了也切。
1.2.3、具體使用
- 定義一個(gè)類PerformanceAop使用@Aspect注解
- @Around("execution(* com.example.perfermance.aop.MyApplication.**(..))")表示需要對(duì) MyApplication中的每一個(gè)方法都做 hook 處理腰湾。
- 記錄方法執(zhí)行前后的時(shí)間戳雷恃,并計(jì)算對(duì)應(yīng)的時(shí)間差。
注意: 關(guān)于 AspectJ 詳細(xì)使用费坊,讀者可以去網(wǎng)上查閱資料倒槐,目前筆者只是實(shí)現(xiàn)計(jì)算方法的耗時(shí)計(jì)算,詳細(xì)的操作并沒有展開分析附井。
@Aspect
public class PerformanceAop {
private static final String TAG = PerformanceAop.class.getSimpleName();
@Around("execution(* com.example.perfermance.aop.MyApplication.**(..))")
public void getTime(ProceedingJoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
//得到方法的名字导犹,例如:MyApplication.attachBaseContext(..)
String name = signature.toShortString();
//記錄方法執(zhí)行前的時(shí)間戳
long startTime = System.currentTimeMillis();
try {
//執(zhí)行該方法
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
//記錄執(zhí)行該方法的時(shí)間
long costTime = System.currentTimeMillis() - startTime;
Log.e(TAG, "method " + name + " cost:" + costTime);
}
}
程序運(yùn)行的結(jié)果:
2019-03-17 20:29:12.946 10094-10094/com.example.perfermance E/PerformanceAop: method MyApplication.attachBaseContext(..) cost:1
2019-03-17 20:29:12.979 10094-10094/com.example.perfermance E/PerformanceAop: method MyApplication.initBugly() cost:12
2019-03-17 20:29:13.002 10094-10094/com.example.perfermance E/PerformanceAop: method MyApplication.initImageLoader() cost:23
2019-03-17 20:29:13.002 10094-10094/com.example.perfermance E/PerformanceAop: method MyApplication.onCreate() cost:35
二唱凯、總結(jié)
我們?cè)诒酒恼轮饕菑某R?guī)的方式和 AOP 的方式來計(jì)算方法的耗時(shí)計(jì)算,而常規(guī)實(shí)現(xiàn)方案可以看出代碼很不優(yōu)雅谎痢,每一個(gè)方法都需要進(jìn)行埋點(diǎn)并且對(duì)項(xiàng)目的侵入性很大磕昼,工作量也很大。而 AOP 這種方式是一個(gè)比較優(yōu)雅的方式實(shí)現(xiàn)的节猿,它對(duì)已有代碼是零侵入性的票从,修改也方便。
記錄于 2019年3月17日