最近产品有个需求就是需要统计前台页面的停留时间,用我们程序员的话来说就是统计Activity在前台的时间,也就是如果程序从启动开始到按home键切换到后台的时候的这段时间内。之前还不知道 ActivityLifecycleCallbacks的时候我就写了一个BaseActivity,然后所有的Activity都去继承该类。但是如果后期项目都已经做好了的话,那在统计的时候就有可能会出现统计不完整的情况,而且最关键的时候有些地方我们使用了Activity,有些地方我们又使用了FragmentActivity这些东西都可能还好的,最坑的是有些地方使用了 PreferenceActivity
ActivityLifecycleCallbacks 使用的好处
以往我们在监测Activity的生活周期的时候,都会在每个Activity的 onCreate() 或者是 onResume() 中进行写代码去监测,后来我们就写了一个基类BaseActivity去做这些处理,但有些时候还是会遇到一些不方便的问题,这个时候我们在想要能有一个统一的东西去管理该多好。还有就是以后我们在使用统计SDK去统计一些信息的时候也不用每个Activity的生命周期都去写一遍了,比如我们之前在使用友盟SDK的时候,可能会在 onResume() 和 onPause() 方法中都会去写统计的代码,特别的麻烦现在直接可以在接口的实现类中实现就行了。s
用法
- 要求API 14+ (Android4.0+)
首先需要集成Application,然后在Manifest.xml里面申明自定义Application
<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:name=".NotifyApplication" > public class NotifyApplication extends Application { @Override public void onCreate() { super.onCreate(); //我们这里可以定义多个的接口监听 registerActivityLifecycleCallbacks(new ActivityLifecycleOne()); registerActivityLifecycleCallbacks(new ActivityLifecycleTwo()); registerActivityLifecycleCallbacks(new ActivityLifecycleThree()); } }
创建一个类去实现 ActivityLifecycleCallbacks并且重写该接口的所有方法,因为我这里会注册多个的监听的,为了测试方便我就抽象出一个基类来,然后其他的ActivityLifecycle都是继承该类
public abstract class BaseActivityLefecycle implements Application.ActivityLifecycleCallbacks { private String Tag = getCallbackTag(); @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { log("onActivityCreated", activity); } @Override public void onActivityStarted(Activity activity) { log("onActivityStarted", activity); } @Override public void onActivityResumed(Activity activity) { log("onActivityResumed", activity); } @Override public void onActivityPaused(Activity activity) { log("onActivityPaused", activity); } @Override public void onActivityStopped(Activity activity) { log("onActivityStopped", activity); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { log("onActivitySaveInstanceState", activity); } @Override public void onActivityDestroyed(Activity activity) { log("onActivityDestroyed", activity); } public void log(String methodName, Activity activity) { Log.i("LOH", methodName + "()..." + activity.getClass().getSimpleName() + "..." + Tag); } public abstract String getCallbackTag(); } public class ActivityLifecycleOne extends BaseActivityLefecycle { @Override public String getCallbackTag() { return "ActivityLifecycleOne"; } } public class ActivityLifecycleTwo extends BaseActivityLefecycle { @Override public String getCallbackTag() { return "ActivityLefecycleTwo"; } } public class ActivityLifecycleThree extends BaseActivityLefecycle { @Override public String getCallbackTag() { return "ActivityLifecycleThree"; } }
最后我们看看通过 log 打印出来的结果
I/LOH: onActivityCreated()...MainActivity...ActivityLifecycleOne I/LOH: onActivityCreated()...MainActivity...ActivityLefecycleTwo I/LOH: onActivityCreated()...MainActivity...ActivityLifecycleThree I/LOH: onActivityStarted()...MainActivity...ActivityLifecycleOne I/LOH: onActivityStarted()...MainActivity...ActivityLefecycleTwo I/LOH: onActivityStarted()...MainActivity...ActivityLifecycleThree I/LOH: onActivityResumed()...MainActivity...ActivityLifecycleOne I/LOH: onActivityResumed()...MainActivity...ActivityLefecycleTwo I/LOH: onActivityResumed()...MainActivity...ActivityLifecycleThree I/LOH: onActivityPaused()...MainActivity...ActivityLifecycleOne I/LOH: onActivityPaused()...MainActivity...ActivityLefecycleTwo I/LOH: onActivityPaused()...MainActivity...ActivityLifecycleThree ........
在结果的显示中我们看到每个Activity的生命周期,由于我们注册了三个接口回调所以我们就可以看到每个生命周期都是三次的打印,从上面的结果其实我们也能大概的猜测出其内部肯定维持这一个List用于保存我们注册的接口回调的。接下来我们就来看看其内部的实现
实现原理
首先在Application的内部维持着一个ActivityLifecycleCallbacks的集合变量,当我们调用注册函数的时候,就会将当前的接口回调添加到集合中。其实ActivityLifecycleCallbacks也没有什么神秘的就是一个简单的Application内部接口而已。
private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
new ArrayList<ActivityLifecycleCallbacks>();
public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
synchronized (mActivityLifecycleCallbacks) {
mActivityLifecycleCallbacks.add(callback);
}
}
//内部接口定义了很多的方法,用于记录Activity的每个生命周期
public interface ActivityLifecycleCallbacks {
void onActivityCreated(Activity activity, Bundle savedInstanceState);
void onActivityStarted(Activity activity);
void onActivityResumed(Activity activity);
void onActivityPaused(Activity activity);
void onActivityStopped(Activity activity);
void onActivitySaveInstanceState(Activity activity, Bundle outState);
void onActivityDestroyed(Activity activity);
}
在Android中FragmentActivity, SupportActivity, ActionBarActivity, AppCompatActivity, PreferenceActivity等等都是继承自Activity的,如果我们要统计任何Activity的生命周期的话,那么我们就可以直接在父类Activity中的每个生命周期的方法中进行统计则是最完美的了。下面分别看看Activity中的每个生命周期的方法的一些内容。
onCreate生命周期
protected void onCreate(Bundle savedInstanceState) { ...... getApplication().dispatchActivityCreated(this, savedInstanceState); }
onStart生命周期
protected void onStart() { ...... getApplication().dispatchActivityStarted(this); }
onDestroy生命周期
protected void onDestroy() { ...... getApplication().dispatchActivityDestroyed(this); }
上面只是我们依次的列举了部分的生命周期其实最后都是大同小异的,我们发现不管在哪个生命周期中最后都会指向Application中的一个特定名字的方法中,我们以onCreate生命周期的为例看看Application内部是如何处理的。
//依次遍历接口集合中的接口变量,然后分别调用接口的不同的生命周期函数。
void dispatchActivityCreated(Activity activity, Bundle savedInstanceState) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ActivityLifecycleCallbacks)callbacks[i]).onActivityCreated(activity,
savedInstanceState);
}
}
}
//这里需要将List集合先转换成一个数组,如果直接操作List的话,会导致在添加和删除集合中的数据的时候会有问题
private Object[] collectActivityLifecycleCallbacks() {
Object[] callbacks = null;
synchronized (mActivityLifecycleCallbacks) {
if (mActivityLifecycleCallbacks.size() > 0) {
callbacks = mActivityLifecycleCallbacks.toArray();
}
}
return callbacks;
}
上面代码中我们可以看到首先将List集合转换成一个Array变量,然后依次遍历所有注册的接口,然后分别的调用不同Activity的具体的生命周期的方法。当我们分别的去实现ActivityLifecycleCallbacks接口并且将其子类注册到application中,我们就可以监听任何一个Activity的每个生命周期了。
问题解决
回到我们最开始的时候如何统计程序的前台停留时间,其实我们只要在自定义的Application中定一个全局的静态变量sCount = 0,如果一个Activity启动的话,则在onActivityStarted方法中sCount++,然后在onActivityStopped()方法中sCount–,最后在onActivityDestroyed的时候判断一下sCount是否等于0表示程序完全退出前台了,还有一种可能就是直接按Home键将程序切换到后台,这个时候你就需要单独的去处理了。其实ActivityLifecycleCallbacks 内部实现是非常简单的,只是在Activity中各个生命周期中调用了接口回调函数,然后Application中定义了接口回调的集合用于保存各个注册的接口。这样子我们定义n多个接口回调,然后分别去分发这些具体的函数。