Application.ActivityLifecycleCallbacks 实现第一次启动、冷启动、热启动、切换后台以及返回前台功能
以下是一个使用 AppLifecycleCallbacks
实现上述功能的示例代码:
import android.app.Application;
import android.os.Bundle;
/**
*
* Description: [ActivityLifecycleCallbacks监听相关首次、冷、热启动、前后台等]
*
*/
public class MyAppLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
private static final String TAG = AppLifecycleCallbacks.class.getSimpleName();
/**
* 只对特定包名下的Activity生效
*/
private static final String PACKAGE_NAME = "com.xxx.cn"; // 替换为您的包名
private Set<Activity> activitySet = new HashSet<>();
/**
* 首次启动严格来说隶属于冷启动,这里之所以单独拎出来,是因为首次启动一般来讲会比非首次启动要久一些,
* 因为首次启动会做一些系统的初始化工作,当然可以把这些初始化工作可以放在IntentService中执行,所以首次启动速度非常重要。
*/
private long firstStartDuration; // 记录首次动时长
/**
* 定义:启动应用时,后台没有该进程,系统会重新创建一个新的进程给该应用。
* <p>
* 首先创建和初始化Application,然后创建和初始化WelcomeActivity,最后显示在界面上。
*/
private long coldStartTime; // 记录冷启动时间
private long coldStartDuration;
/**
* 2、热启动
* <p>
* 定义:从已有的进程启动应用,叫热启动。启动应用时,
* 后台有该应用的进程(比如按下home键、back键,应用虽然退出,但是该应用的进程会保存在后台);
* <p>
* 热启动因为是从已有的进程中启动,所以不会执行 Application,而是直接执行MainActivity的逻辑,
* 热启动不用创建和初始化Application,因为一个应用从进程的创建到销毁,Application只会初始化一次;
*/
private long hotStartTime = 0; // 记录热启动时间
private long hotStartDuration;
private int activityCount = 0;
private int account = 0;
/**
* true--后台; false--前台
*/
private boolean isRunInBackground = false;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
LogUtils.logd(TAG, "========================= 当前的onActivityCreated:" + activity.getClass().getSimpleName());
if (isActivityFromSpecificPackage(activity)) {
activitySet.add(activity);
activityCount++;
if (activityCount == 1) { // 应用从后台进入前台,记录启动时间
coldStartTime = System.currentTimeMillis();
}
}
}
@Override
public void onActivityStarted(Activity activity) {
if (isActivityFromSpecificPackage(activity)) {
account++;
LogUtils.logd(TAG + "===== " + activity.getIntent().getFlags() + "==========isTaskRoot=======" + activity.isTaskRoot());
if (isRunInBackground && !activity.isTaskRoot()) {
// 后台到前台,在此进行相应操作
setAppIsRunInBackground(activity, false);
LogUtils.logd(TAG + "========================= 当前的Activity: 后台》》》前台,在此进行相应操作 " + activity.getClass().getSimpleName());
}
if (1 == account) { // 首次或切换到桌面或其他应用或熄屏等情况,再次返回打开APP时
hotStartTime = System.currentTimeMillis();
LogUtils.logd(TAG + "========================= 当前的Activity 检查是否是热启动: 后台》》》前台,在此进行相应操作 " + activity.getClass().getSimpleName());
}
}
}
@Override
public void onActivityResumed(Activity activity) {
if (isActivityFromSpecificPackage(activity)) {
long duration = System.currentTimeMillis();
if (1 == activityCount) {
if (null != activity && activity instanceof SplashActivity) {// 冷启动初始化Application,然后创建和初始化WelcomeActivity,最后显示在界面上
boolean isFirstUseAppStartFlag = ((SplashActivity) activity).isFirstUseAppStartFlag();
if (isFirstUseAppStartFlag) {
setAppFirstStartDuration(activity, coldStartTime, duration);
}
setAppColdStartDuration(activity, coldStartTime, duration);
} else if (1 == account) {
setAppHotStartDuration(activity, hotStartTime, duration);
}
}
}
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
if (isActivityFromSpecificPackage(activity)) {
activitySet.remove(activity);
account--;
if (account == 0) {
// 前台到后台,在此进行相应操作
setAppIsRunInBackground(activity, true);
LogUtils.logd(TAG + "========================= 当前的Activity: 前台》》》后台,在此进行相应操作 " + activity.getClass().getSimpleName());
}
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if (isActivityFromSpecificPackage(activity)) {
activitySet.remove(activity);
activityCount--;
if (activityCount < 1 && isRunInBackground) {
setAppExistMark(activity, true);
LogUtils.logd(TAG + "========================= 当前正常点击退出APP");
}
}
}
/**
* 设置首次启动时长
*
* @param activity
* @param startTime
* @param endTime
*/
public void setAppFirstStartDuration(Activity activity, long startTime, long endTime) {
firstStartDuration = endTime - startTime;
// LogUtils.logd(TAG, "========first start time: " + firstStartDuration + "ms");
}
/**
* 设置冷启动时长
*
* @param activity 必须是 activity instanceof WelcomeActivity
* @param startTime
* @param endTime
*/
public void setAppColdStartDuration(Activity activity, long startTime, long endTime) {
coldStartDuration = endTime - startTime;
// LogUtils.logd(TAG, "========Cold start time: " + coldStartDuration + "ms");
}
/**
* 设置热启动时长
*
* @param activity
* @param startTime
* @param endTime
*/
public void setAppHotStartDuration(Activity activity, long startTime, long endTime) {
hotStartDuration = endTime - startTime;
// LogUtils.logd(TAG, "========holt start time: " + hotStartDuration + "ms");
}
/**
* 设置前台后台
*
* @param flag true--后台; false--前台
* @return true--后台; false--前台
*/
public boolean setAppIsRunInBackground(Activity activity, boolean flag) {
isRunInBackground = flag;
return flag;
}
/**
* 退出App 正常点击退出; 但是kill时是无法监听的
* @param activity
* @param flag
* @return
*/
public boolean setAppExistMark(Activity activity, boolean flag) {
isRunInBackground = flag;
return flag;
}
/**
* isActivityFromSpecificPackage方法用于检查传入的Activity是否属于指定的包名。
* 如果是,则将该Activity添加到activitySet集合中,并在其生命周期回调事件中执行相应的逻辑。
* 如果不是,则不执行任何操作。
* @param activity
* @return
*/
private boolean isActivityFromSpecificPackage(@NonNull Activity activity) {
Intent componentName = new Intent(activity, activity.getClass());
PackageManager packageManager = activity.getPackageManager();
ResolveInfo resolveInfo = packageManager.resolveActivity(componentName, 0);
if (resolveInfo != null && resolveInfo.activityInfo.packageName.equals(PACKAGE_NAME)) {
return true;
}
return false;
}
}
在上述代码中:
- 通过一个布尔值
isFirstLaunch
来标识是否是第一次启动。 - 记录活动上次处于前台的时间,通过与当前时间的比较来判断是冷启动还是热启动。
在实际应用中,您可以根据具体的需求在相应的回调方法中添加更多的逻辑,比如记录日志、进行性能统计、处理资源释放等操作。例如,如果是冷启动,您可能需要进行一些初始化操作,而热启动则可以跳过一些已经完成的初始化步骤以提高启动速度。