APM之Android應用的啓動次數(1)

 轉載請說明.java

  一款應用的啓動次數,無疑是一項重要的APM的檢測指標.但Android的啓動次數要考慮到一個重要的因素.那就是從後臺切換回前臺的時候.這算一次新的啓動嗎?app

  友盟和NewRelic做爲國內外2家這項數據檢測的領頭羊,採用的方法是相似的.可是實現手段徹底不同. this

 友盟和newRelic的實現方法:

  友盟須要用戶本身在代碼中,用戶手工寫代碼嵌入Activity生命週期的onPause()和onResume()方法中,執行先後臺切換監視的邏輯.spa

  newRelic的用戶徹底無需用戶關心這個.它會在編譯時期自動在Activity的生命週期的onStop()和onStart()方法中嵌碼.線程

  App先後臺切換的超時時間也不同.友盟是30s,newRelic是5s.code

 newRelic的實現原理:

  經過ASM技術.在用戶打包apk的時候動態嵌碼.這裏的實現原理之後再講.blog

  用戶若是使用了newRelic的sdk後,會發如今系統的Activity的子類中onCreate()和onStop(),onStart()方法中都嵌碼了. onCreate()方法的嵌碼和Activity的交互Trace有關.暫不討論.生命週期

sdk初始化的時候會執行下面的邏輯get

  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().it

  因此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()方法.

  而Activity生命週期的方法都是在主線程執行的.能夠認爲如下流程是線性的.因此A切換到B的時候 是先運行A的onCreate()->OnStart()->OnResume()以後纔會運行B的OnStop()方法.

相關文章
相關標籤/搜索