android开发之app在线时长统计sdk开发
引言:
很多app的在线时长统计都是通过在activity的生命周期中埋点来完成的。我这里既然是封装成sdk,当然就不能这样来了。封装sdk的规则,我想大家都清楚,入参尽量少,回调尽量全,权限尽量不要有。
需求分析:
作为sdk,最好是在Application中初始化,入参,当然是applicationcontext为好,为啥?生命周期长呀。我这sdk作为观察app的在线时长的,当然不能随便就被回收了。然后是权限问题,低调,才会有人用。不然,用户被你一堆权限吓跑了。
既然不能再每个activity中埋点监听状态,那只好通过ApplicationContext找方法了。看看有没有能够监听全局的方法。一查api,还真有。那就开始造轮子。
实践:
给个API所在地址:http://www.android-doc.com/reference/android/app/Application.html
找找方法呗:
看到没,该方法很直接呀:activity生命周期回调。有了这个,大事可期!!!
在点进去看看详情,确认一下:
My god ,I love it ! 简直是饿了送鸡腿,困了送枕头呀。
1.分析生命周期的场景
1.activity被后台后强杀,结束,上报时长日志。
2.activity一层层的退出干净后,结束,上报时长日志。
2.撸代码
根据这两个场景,立马就开动了,使用一个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 下载地址: