在優(yōu)化之前首先得有一個(gè)量化的過程余赢,不然很難知道我們的優(yōu)化有沒有結(jié)果东羹,不能總是靠感覺岔冀,就像看大師炒菜个榕,大師告訴你放適量的鹽一樣蛋疼篡石。
工具選擇
知道了啟動(dòng)和頁面渲染的時(shí)間我們還得去找具體的位置,要是順便能定位位置就好了 西采,抱著這種心態(tài)凰萨,一開始我就瞄準(zhǔn)的第三方的開源庫,大概找了下有騰訊的# Matrix和360的# ArgusAPM械馆。但看到GitHub上的上次更新時(shí)間胖眷,瞬間有種情況不是很樂觀的感覺。
尤其是360這個(gè)霹崎,去年開源珊搀,上次更新就是9月前,跟不維護(hù)差不多了尾菇,再去issue里看看境析,情況真的不容樂觀:
瞬間感覺自己攤上大事了囚枪,我還只是個(gè)孩紙啊,行吧劳淆,我們再去看看騰訊大哥的Matrix吧
大哥就是大哥链沼,那還等啥,擼吧沛鸵。
一頓操作猛如虎括勺,一看BUG有2個(gè)痛點(diǎn)
1.沒辦法像Matrix的demo那樣統(tǒng)計(jì)啟動(dòng)之類的時(shí)間,因?yàn)楣こ逃玫氖茿ndroidX
2.每次修改類都需要clean一次工程谒臼,這個(gè)很耗時(shí)間啊
看了下issue朝刊,發(fā)現(xiàn)不少反饋這樣的問題,都沒有得到官方正式的回復(fù)蜈缤,哎拾氓,好難,沒辦法只能自己搞了底哥。
自己寫簡陋版時(shí)間統(tǒng)計(jì)
自己搞雖然沒有Matrix這樣可以很快的定位到問題咙鞍,但也是有自己的優(yōu)勢的,比如編譯快趾徽。加入Matrix的Trace模塊可以明顯感受到編譯慢了很多要1m18s续滋,而正常調(diào)試編譯的時(shí)候只需要38s左右,這是因?yàn)榫幾g期間trace模塊會(huì)會(huì)自動(dòng)在每個(gè)方法是開始和結(jié)束加入時(shí)間統(tǒng)計(jì)的標(biāo)識(shí)孵奶,這樣方便我們定位問題疲酌。
主要統(tǒng)計(jì)的就是application創(chuàng)建時(shí)間、啟動(dòng)頁(Splash)時(shí)間了袁、第一個(gè)Activity渲染完成的時(shí)間朗恳。
最近負(fù)責(zé)項(xiàng)目的啟動(dòng)順序
application初始化一些庫=》Splash(一個(gè))=》MainActivity(FirstActivity)
當(dāng)前Activity加載完成的標(biāo)志是參考Matrix里的代碼,發(fā)現(xiàn)在Activity的onWindowFocusChange()里面有特別的插樁代碼载绿,源碼里的注釋也證實(shí)了觀點(diǎn)粥诫,之所以不支持AndroidX,估計(jì)就是忘了在對(duì)應(yīng)的地方插代碼了
統(tǒng)計(jì)Activity頁面加載時(shí)間
因?yàn)橛蠦aseActivity崭庸,所以從這著手怀浆,在onCreate時(shí)記錄,在第一次獲得焦點(diǎn)時(shí)結(jié)束怕享,統(tǒng)計(jì)時(shí)間差执赡,大概就是Activity的頁面加載時(shí)間了
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
timeOnCreate = System.currentTimeMillis();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (isFirstFocus && hasFocus){
TraceHelper.get().onWindowFocusChange(tag,System.currentTimeMillis()-timeOnCreate);
isFirstFocus=false;
}
}
統(tǒng)計(jì)一次冷啟動(dòng)時(shí)間
application創(chuàng)建時(shí)間=splashOnCreate()-start()
Splash渲染時(shí)間=onWindowFocusChange()-onCreate()
Splash停留的時(shí)間=mainActivityOnCreate()-splashOnCreate()
MainActivity渲染時(shí)間=onWindowFocusChange()-onCreate()
冷啟動(dòng)時(shí)間=MainActivityonWindowFocusChange()-applicationOnCreate()
自己項(xiàng)目的統(tǒng)計(jì)效果:測試機(jī)器Redmi5(驍龍450+3gRAM),缺少了Splash的頁面渲染時(shí)間熬粗,而我在oncreat方法里面就設(shè)置了跳轉(zhuǎn)搀玖,推測是這樣沒有獲得焦點(diǎn),MainActivity有3秒驻呐,有很大優(yōu)化空間了
統(tǒng)計(jì)方法時(shí)間
通過上面的過程灌诅,我們得到了一個(gè)總體的時(shí)間芳来,我們想細(xì)化定位的話還得知道這個(gè)過程里方法執(zhí)行的時(shí)間,由于方法數(shù)比較多猜拾,而且方法統(tǒng)計(jì)在整個(gè)項(xiàng)目都有用到的地方即舌,肯定就不能再像上面那樣自己寫了,由于時(shí)間緊我還沒有找到一個(gè)合適的第三方庫挎袜,只能等Matrix修復(fù)或者你們有更好的也可以在評(píng)論里分享一下
最后附上本次的工具類:
/**
* create by z on 19/12/27
*
* @author z
*/
public class TraceHelper {
private boolean isEnable = true;
private static TraceHelper instance;
private long startTime;
private long splashOnCreateTime;
private long mainActivityTime;
private long completeTime;
private Map<String,Long> activityRenderTimes=new HashMap<>();
private TraceHelper() {
}
public static TraceHelper get() {
if (instance == null) {
synchronized (TraceHelper.class) {
if (instance == null) {
instance = new TraceHelper();
}
}
}
return instance;
}
private long getTime(){
return System.currentTimeMillis();
}
public void start() {
startTime = getTime();
}
public void splashOnCreate() {
splashOnCreateTime = getTime();
}
public void mainActivity(){
mainActivityTime = getTime();
}
@SuppressLint("DefaultLocale")
public void onWindowFocusChange(String tag, long timeMist) {
Log4jUtils.d(this,String.format("onWindowFocusChange--tag[%s]-----time[%d]",tag,timeMist));
activityRenderTimes.put(tag,timeMist);
//冷啟動(dòng)時(shí)間
if (tag.contains("MainActivity")){
complete();
}
}
private void complete(){
if (isEnable){
completeTime=getTime();
show();
}
}
public void show(){
Log4jUtils.d(this,"------------------------------------------------");
Log4jUtils.d(this,"--applicationCreateTime: "+(splashOnCreateTime-startTime));
Log4jUtils.d(this,"--SplashStayTime: "+(mainActivityTime -splashOnCreateTime));
Log4jUtils.d(this,"--completeTime: "+(completeTime-startTime));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
activityRenderTimes.forEach((s, aLong) -> {
Log4jUtils.d(this,"--"+s+": "+aLong);
});
}
Log4jUtils.d(this,"------------------------------------------------");
}
}