
ActivityLifecycleCallbacks 是用來(lái)監(jiān)聽(tīng)所有 Activity 的生命周期回調(diào)。接口定義如下:
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);
}
Activity 的每一個(gè)生命周期都對(duì)應(yīng) ActivityLifecycleCallbacks 接口中的一個(gè)方法,比如 onActivityCreated 回調(diào)是在 Activity 的 onCreate 方法中調(diào)用 getApplication().dispatchActivityCreated(this, savedInstanceState) 完成對(duì) Activity 生命周期跟蹤監(jiān)聽(tīng)。
ActivityLifecycleCallbacks 使用
- 要求 API 14+
package com.sunpeng.lifecycle;
import android.app.Application;
/**
* Created by sunpeng on 17/6/2.
*/
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// AppLifecycleCallback 實(shí)現(xiàn) ActivityLifecycleCallbacks 接口方法
this.registerActivityLifecycleCallbacks(new AppLifecycleCallback());
}
}
探究在 Android 中的應(yīng)用
- 應(yīng)用新開(kāi)進(jìn)程假重啟處理(低內(nèi)存回收、修改權(quán)限)
- 管理 Activity 頁(yè)面棧
- 獲取當(dāng)前 Activity 頁(yè)面
- 判斷應(yīng)用前后臺(tái)
- 保存恢復(fù)狀態(tài)值 savedInstanceState
- 頁(yè)面分析統(tǒng)計(jì)埋點(diǎn)
結(jié)合 ActivityLifecycleCallbacks ,實(shí)現(xiàn)了以上的一些功能,完整源碼可以查看AppLifecycleCallback。
1、應(yīng)用新開(kāi)進(jìn)程假重啟處理(低內(nèi)存回收、修改權(quán)限)
應(yīng)用在低內(nèi)存的情況下退出重新啟動(dòng),并不會(huì)執(zhí)行正常的啟動(dòng)流程,而是創(chuàng)建新的進(jìn)程,直接還原上一次的操作頁(yè)面。比如:
- 當(dāng)前操作頁(yè)面:
LoginActivity - 正常啟動(dòng)使用流程:
SplashActivity -> MainActivity -> LoginActivity - 低內(nèi)存重啟流程:** 新開(kāi)進(jìn)程,直接啟動(dòng)
LoginActivity**
** 低內(nèi)存重啟流程存在的問(wèn)題:**頁(yè)面棧信息丟失,頁(yè)面顯示以及返回跳轉(zhuǎn)異常;MainActivity 可能沒(méi)有執(zhí)行,部分功能不會(huì)初始化。
** 解決思路:** 通過(guò)監(jiān)聽(tīng)回調(diào)方法 onActivityCreated,判斷應(yīng)用啟動(dòng)的第一個(gè) Activity 頁(yè)面是否為 LauncherActivity,如果不是,則強(qiáng)制啟動(dòng) LauncherActivity 來(lái)執(zhí)行正常的啟動(dòng)流程。
// AppLifecycleCallback.java
private static final int APP_STATUS_UNKNOWN = -1;
private static final int APP_STATUS_LIVE = 0;
private int appStatus = APP_STATUS_UNKNOWN;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (appStatus == APP_STATUS_UNKNOWN) {
// 設(shè)置狀態(tài)標(biāo)志 APP_STATUS_LIVE
appStatus = APP_STATUS_LIVE;
// 判斷是否跳轉(zhuǎn)閃屏頁(yè)
startLauncherActivity(activity);
}
}
private static void startLauncherActivity(Activity activity) {
try {
Intent launchIntent = activity.getPackageManager().getLaunchIntentForPackage(activity.getPackageName());
String launcherClassName = launchIntent.getComponent().getClassName();
String className = activity.getComponentName().getClassName();
if (TextUtils.isEmpty(launcherClassName) || launcherClassName.equals(className)) {
return;
}
Log.e(TAG, "launcher ClassName --> " + launcherClassName);
Log.e(TAG, "current ClassName --> " + className);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
activity.startActivity(launchIntent);
activity.finish();
} catch (Exception e) {
e.printStackTrace();
}
}
** 驗(yàn)證方式:**
1、 通過(guò) Android Studio 工具 Android Device Monitor 模擬殺死當(dāng)前應(yīng)用進(jìn)程。(Tools -> Android -> Android Device Monitor)

2、App 退到后臺(tái),修改應(yīng)用權(quán)限(6.0 以上系統(tǒng)),再次 App 回到前臺(tái),同樣會(huì)出現(xiàn)應(yīng)用新開(kāi)進(jìn)程重啟。
2、管理 Activity 頁(yè)面棧
Activity 頁(yè)面棧,最常用的實(shí)現(xiàn)就是用來(lái)完全退出應(yīng)用。ActivityLifecycleCallbacks 和 Stack 來(lái)管理所有的Activity,不僅方便集中管理存儲(chǔ) Activity 實(shí)例,也不容易造成內(nèi)存泄露。
監(jiān)聽(tīng)回調(diào)方法 onActivityCreated 和 onActivityDestroyed 添加刪除 Actvity 實(shí)例。
// AppLifecycleCallback.java
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
ActivityStackManager.getInstance().addActivity(activity);
}
@Override
public void onActivityDestroyed(Activity activity) {
ActivityStackManager.getInstance().removeActivity(activity);
}
// ActivityStackManager.java
public void addActivity(Activity activity){
if (activities == null) {
activities = new Stack<Activity>();
}
if (activities.search(activity) == -1) {
activities.push(activity);
}
}
public void removeActivity(Activity activity){
if (activities != null && activities.size()>0){
activities.remove(activity);
}
}
3、獲取當(dāng)前 Activity 頁(yè)面
React Native 開(kāi)發(fā),我們經(jīng)常需要獲取當(dāng)前的 TopActivity 實(shí)例,用來(lái)彈出安全鍵盤、RN接口通信等。關(guān)于獲取當(dāng)前Activity的一些思考詳細(xì)介紹了一些思路,結(jié)合具體實(shí)現(xiàn),推薦兩個(gè)實(shí)現(xiàn)思路:** 弱引用持有當(dāng)前 Activity 實(shí)例和 Activity 頁(yè)面棧方式。**
通過(guò)監(jiān)聽(tīng)回調(diào)方法 onActivityResumed,設(shè)置當(dāng)前 Activity 頁(yè)面
// AppLifecycleCallback.java
@Override
public void onActivityResumed(Activity activity) {
// 弱引用持有當(dāng)前 Activity 實(shí)例
ActivityStackManager.getInstance().setCurrentActivity(activity);
// Activity 頁(yè)面棧方式
ActivityStackManager.getInstance().setTopActivity(activity);
}
** 疑問(wèn):為什么 Activity 頁(yè)面棧方式還需要在 onActivityResumed 中設(shè)置當(dāng)前 Activity 頁(yè)面?
** 答疑:當(dāng)關(guān)閉 B 頁(yè)面返回 A 頁(yè)面時(shí),首先 A 頁(yè)面的 onResume 會(huì)先執(zhí)行,然后才會(huì)調(diào)用 B 頁(yè)面的 onDestroy。
再來(lái)看看 ActivityStackManager 是怎么實(shí)現(xiàn)獲取當(dāng)前 Activity 頁(yè)面
// ActivityStackManager.java
private WeakReference<Activity> sCurrentActivityWeakRef;
public Activity getCurrentActivity() {
Activity currentActivity = null;
if (sCurrentActivityWeakRef != null) {
currentActivity = sCurrentActivityWeakRef.get();
}
return currentActivity;
}
public void setCurrentActivity(Activity activity) {
sCurrentActivityWeakRef = new WeakReference<Activity>(activity);
}
public Activity getTopActivity(){
if (activities != null && activities.size() > 0) {
return activities.peek();
}
return null;
}
public void setTopActivity(Activity activity){
if (activities != null && activities.size() > 0) {
if (activities.search(activity) == -1) {
activities.push(activity);
return;
}
int location = activities.search(activity);
if (location != 1) {
activities.remove(activity);
activities.push(activity);
}
}
}
4、判斷應(yīng)用前后臺(tái)
判斷應(yīng)用是否在后臺(tái)運(yùn)行,針對(duì)前后臺(tái)運(yùn)行會(huì)做一些處理,比如提示用戶應(yīng)用運(yùn)行在后臺(tái)、以及應(yīng)用前后臺(tái)切換回調(diào)通知等。業(yè)務(wù)場(chǎng)景非常多,對(duì)于開(kāi)發(fā)而言就是提供穩(wěn)定可靠的檢測(cè)前后臺(tái)方法,避免出現(xiàn)機(jī)型不兼容問(wèn)題。
AndroidProcess 提供 6 種方法判斷 App 位于前臺(tái)或者后臺(tái)。利用
ActivityLifecycleCallbacks 實(shí)現(xiàn)的方式簡(jiǎn)單有效兼容性好,也不要需要申請(qǐng)權(quán)限。
// AppLifecycleCallback.java
private int appCount = 0;
private boolean isForground = true;
@Override
public void onActivityStarted(Activity activity) {
appCount++;
if (!isForground) {
isForground = true;
Log.e("AppLifecycle", "app into forground ");
}
}
@Override
public void onActivityStopped(Activity activity) {
appCount--;
if (!isForgroundAppValue()) {
isForground = false;
Log.e("AppLifecycle", "app into background ");
}
}
private boolean isForgroundAppValue() {
return appCount > 0;
}
5、保存恢復(fù)狀態(tài)值
Activity 異常退出經(jīng)常需要保存恢復(fù)一些數(shù)據(jù),ActivityLifecycleCallbacks 實(shí)現(xiàn)數(shù)據(jù)保存恢復(fù)也是比較簡(jiǎn)單的。
// AppLifecycleCallback.java
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (savedInstanceState != null && savedInstanceState.getBoolean("saveStateKey", false)) {
Log.e(TAG, "localTime --> " + savedInstanceState.getLong("localTime"));
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
outState.putBoolean("saveStateKey", true);
outState.putLong("localTime", System.currentTimeMillis());
}