不少app的在線時長統計都是經過在activity的生命週期中埋點來完成的。我這裏既然是封裝成sdk,固然就不能這樣來了。封裝sdk的規則,我想你們都清楚,入參儘可能少,回調儘可能全,權限盡可能不要有。css
做爲sdk,最好是在Application中初始化,入參,固然是applicationcontext爲好,爲啥?生命週期長呀。我這sdk做爲觀察app的在線時長的,固然不能隨便就被回收了。而後是權限問題,低調,纔會有人用。否則,用戶被你一堆權限嚇跑了。html
既然不能再每一個activity中埋點監聽狀態,那隻好經過ApplicationContext找方法了。看看有沒有可以監聽全局的方法。一查api,還真有。那就開始造輪子。java
給個API所在地址:http://www.android-doc.com/reference/android/app/Application.htmlandroid
找找方法唄:
api
看到沒,該方法很直接呀:activity生命週期回調。有了這個,大事可期!!!markdown
在點進去看看詳情,確認一下:app
My god ,I love it ! 簡直是餓了送雞腿,困了送枕頭呀。ide
1.activity被後臺後強殺,結束,上報時長日誌。this
2.activity一層層的退出乾淨後,結束,上報時長日誌。.net
根據這兩個場景,立馬就開動了,使用一個map來記錄activity的啓動和結束,再用幾個flag標記切換生命週期。可是,一通下來,發現,沒這麼簡單呀。要考慮的東西真多。
首先,要對啓動模式進行考慮。standard模式,A-B-A,生命週期,這個你們應該很熟。可是singletask就在監聽中有了變化。A-B-A過程當中,A的onActivityStarted(Activity activity)方法中,activity並非你們期待的b的實例,而是a的實例。固然還有不少其餘問題。不一一贅述。代碼是最好的老師。
核心代碼:
package com.ailin.shoneworn.OnLineStatics; import android.app.Activity; import android.app.Application; import android.content.Context; import android.os.Bundle; import java.util.HashMap; import java.util.Map; /** * Created by admin on 2018/3/2. * @author chenxiangxiang * shoneworn@163.com * 轉載註明出處:http://www.cnblogs.com/shoneworn */ class OnLineStatisticsClass { private String TAG = "OnlineStatics"; private boolean isAppAlive = true; //judge is app alive; private boolean isSwitchActivity = false; // judge is switch activity from top to other in the stack of activity private boolean isAppExit = false; //some times app have cleard the stack of activity but app is not exit . this boolean can help to static realive; private String topActivity ; private Map<String ,String> map = new HashMap<>(); private long timeStart =0; //start tag timestemp private OnLineImpl impl; //set a callback public void init(final Context context){ Application application = (Application)context.getApplicationContext(); timeStart = System.currentTimeMillis()/1000; application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle bundle) { topActivity = activity.getClass().getSimpleName(); map.put(topActivity,topActivity); isAppAlive = true; isSwitchActivity = false; } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { //do you know why this logic is used here? because of the launch mode ,when activity start with SingleTask mode ,the onActivityStarted callback a top activity . if(!activity.getClass().getSimpleName().equals(topActivity)){ isSwitchActivity = true; }else{ isSwitchActivity = false; } topActivity=activity.getClass().getSimpleName(); .......................... } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { if(activity.getClass().getSimpleName().equals(topActivity) ){ if(!isSwitchActivity||map.size()==1){ ................... } } } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { map.remove(activity.getClass().getSimpleName()); if(map.size()==0&&isAppAlive){ long timeEnd = System.currentTimeMillis()/1000; if(impl!=null){ long timegap = timeEnd-timeStart; String onlineTime = String.valueOf(timegap); impl.onReportDuration(onlineTime); timeStart = System.currentTimeMillis()/1000; } isAppAlive = false; } if(map.size() ==0){ isAppExit = true; } } }); } public void setOnLineImpl(OnLineImpl impl){ this.impl = impl; } }
demo 下載地址: