不少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 下载地址: