標籤:
轉載請說明.
一款應用的啟動次數,無疑是一項重要的APM的檢測指標.但Android的啟動次數要考慮到一個重要的因素.那就是從後台切換回前台的時候.這算一次新的啟動嗎?
友盟和NewRelic作為國內外2家這項資料檢測的領頭羊,採用的方法是類似的.但是實現手段完全不一樣.
友盟和newRelic的實現方法:
友盟需要使用者自己在代碼中,使用者手工寫代碼嵌入Activity生命週期的onPause()和onResume()方法中,執行newRelic的邏輯.
newRelic的使用者完全無需使用者關心這個.它會在編譯時間期自動在Activity的生命週期的onStop()和onStart()方法中嵌碼.
認為App前後台切換的時間也不一樣.友盟是30s,newRelic是5s.
newRelic的實現原理:
通過ASM技術.在使用者打包apk的時候動態嵌碼.這項功能的實現以後再講.
使用者如果使用了newRelic的sdk後,會發現在系統的Activity的子類中onCreate()和onStop(),onStart()方法中都嵌碼了. onCreate()方法的嵌碼和Activity的互動Trace有關.暫不討論.
開始的時候.
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("AppStateMon")); this.activitySnoozeTimeInMilliseconds = snoozeTimeInMilliseconds; executor.scheduleAtFixedRate(this, initialDelay, period, timeUnit); //sdk初始化的時候開始執行,以固定頻率執行看門狗邏輯.檢測app是否進入後台.(預設5s檢測一次,打盹超過5s認為進入後台)
public void run() { synchronized (this.foregroundLock) { if ((this.foregrounded) && (getSnoozeTime() >= this.activitySnoozeTimeInMilliseconds)) { //如果app現在在前台但打盹時間大於規定時間.認為應用已經進入後台. notifyApplicationInBackground(); this.foregrounded = false; } } }
private long getSnoozeTime() //打盹時間 { synchronized (this.foregroundLock) { synchronized (this.snoozeLock) { if (this.snoozeStartTime == 0L) return 0L; return (System.currentTimeMillis() - this.snoozeStartTime); } } }
嵌入在使用者的Activity的代碼中.onStop()方法被嵌入了ApplicationStateMonitor.activityStopped(), onStart()方法嵌入了ApplicationStateMonitor.activityStarted().
所以Activity執行生命週期的2個方法時.會順帶執行以下2個方法.
public void activityStopped() { synchronized (this.foregroundLock) { synchronized (this.snoozeLock) { this.count -= 1L; if (this.count == 0L) //最關鍵的地方.如果應用進入後台,打盹時間才開始記錄 this.snoozeStartTime = System.currentTimeMillis(); } } } public void activityStarted() { synchronized (this.foregroundLock) { synchronized (this.snoozeLock) { this.count += 1L; if (this.count == 1L) { this.snoozeStartTime = 0L; } } if (!(this.foregrounded)) { //如果app原來沒在前台,則通知SDK已經進入前台.資料收集工作再次執行. log.verbose("Application appears to be in the foreground"); notifyApplicationInForeground(); this.foregrounded = true; } } }
上面邏輯走的通的一個重要原因是;一個ActivityA切換到另一個ActivityB,然後然後走的生命週期流程如下:
A.onStart()---->B.onCreate()-->B.onStart()--->A.onStop()-------(按home鍵進入後台)>B.onStop()----->B.onDestroty()
count=1 ------------------->count=2--------->count=1---------------------------->count=0--->打盹時間的初始值開始確定為目前時間
2個Activity的生命週期是重疊的.所以Activity切換的時候不會認為app在打盹. 一個Activity的展示產生是在生命週期的onResume()中.而使用者的介面完全看不到才執行Activity的onStop()方法.
APM之Android應用的啟動次數(1)