1. 程式人生 > >Activity生命週期監聽介面:ActivityLifecycleCallbacks

Activity生命週期監聽介面:ActivityLifecycleCallbacks

1. 需求場景

專案遇到新需求:給App設定指紋解鎖或者手勢密碼解鎖,例如,App切換至後臺或者程序關閉,時間如果超過20sec,App再次切換至前臺或者重新開啟,要讓使用者驗證指紋或者手勢密碼,驗證通過的話才能進入home頁,當然,具體的時間長短,後端可配。

2. 方案分析

記錄App切換至後臺或程序被殺死的時間點是解決問題的關鍵點一,假設這個時間點是T1;記錄App再次切換至前臺或者重新開啟的時間點是解決問題的關鍵點二,假設這個時間點是T2。只要能準確的記錄T1和T2,上述需求就迎刃而解(假設後端配置的時間間隔為timeSpan)。
if (T1-T2>timeSpan){
    // 超時,驗證指紋或者手勢密碼
}

3. 監聽T1和T2的基本思路

(1).寫一個基類BaseActivity,所有新建立的Activity全都繼承基類;

(2).在基類中定義一個int變數activeNum,記錄當前存活的Activity個數;

(3).回撥基類的onResume()方法,activeNum就加1,回撥基類的onStop()方法, activeNum就減1;

(4).當activeNum的值減到0,說明App進入後臺或者被Kill,記錄時間點T1並儲存.因為App不同頁面間切換都會走onResume(),所以在記錄時間點T1的同時,儲存一個標記checkTimeFlag, 置為true,這個標記用來判斷下次呼叫onResume()時是否為T2時間點

(5).在基類的onResume()方法裡獲取並判斷標記checkTimeFlag,true的話,獲取App切換到前臺或者重新開啟的時間點T2,檢查是否超時,超時的話,將標記checkTimeFlag置為false並驗證使用者指紋或者手勢密碼;

(6).配置的時間間隔timeSpan可以在啟動頁從後端獲取,每次走啟動頁的時候重新整理一次,當然個別場景會有些延遲,例如,使用者從頁面A進入後臺,timeSpan修改了,但是使用者切回前臺,判斷時使用的timeSpan還是上次的,不是修改後的,這種場景不走啟動頁重新整理timeSpan,如果非要實時的話,其實可以把介面請求寫在onResume()裡,獲取T2之後,請求介面獲取timeSpan。

通過控制BaseActivity的onResume()和onStop()方法實現需求是可以的,但是,這個方法要求所有Activity都必須繼承基類,而且在BaseActivity中實現這樣的邏輯顯然不太好,程式碼會顯得臃腫。其實,Android為我們提供了一個非常好的介面:ActivityLifecycleCallbacks來監聽Activity的生命週期方法,把上述思路放到介面的回撥方法裡是再好不過的。

4.ActivityLifecycleCallbacks使用方法


1)定義類 AppLifecycleCallbacks implements ActivityLifecycleCallbacks

public class AppLifecycleCallbacks implements ActivityLifecycleCallbacks {
    private int activeNum;
    private int timeSpan = 15;
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    }
    public void onActivityStarted(Activity activity) {
    }
    public void onActivityResumed(Activity activity) {
        if ((boolean) SPUtils.get(activity, "checkTimeoutFlag", false)) {
            SPUtils.put(activity, "checkTimeoutFlag", false);
checkTimeout(activity);
}
        activeNum += 1;
}
    public void checkTimeout(Context context) {
        long enterTime = System.currentTimeMillis();
        long stopTime = (long) SPUtils.get(context, "stopTime", 0l);
// Todo
// 需要實時的話,請求介面獲取timeSpan放在這裡做
LogUtil.Log("jacob", "enterTime:" + enterTime + "----stopTime:" + stopTime +
                "----" + (enterTime - stopTime));
        if (enterTime - stopTime > timeSpan * 1000) {
            ComponentsManager.toVerifyFingerprint(context);
}
    }
    @Override
public void onActivityPaused(Activity activity) {
    }
    public void onActivityStopped(Activity activity) {
        activeNum -= 1;
        if (activeNum == 0) {
            long stopTime = System.currentTimeMillis();
LogUtil.Log("jacob", "stopTime" + stopTime);
SPUtils.put(activity, "stopTime", stopTime);
SPUtils.put(activity, "checkTimeoutFlag", true);
}
    }
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    }
    public void onActivityDestroyed(Activity activity) {
    }
}

(2)自定義類 CustomApplication extends Application 

在onCreate()中註冊監聽實現類

registerActivityLifecycleCallbacks(new AppLifecycleCallbacks());

(3)修改AndroidManifest.xml中Application

<applicationandroid:name=".CustomApplication"

5. 感言

第一次寫Blog,沒什麼經驗。腦子裡一堆想法,真要寫下來,蠻難的,先從簡單的寫起,再接再厲,希望一次比一次好。