1. 程式人生 > >Android 監聽APP進入後臺或切換到前臺方案對比

Android 監聽APP進入後臺或切換到前臺方案對比

api 5.0 等等 推薦一個 情況 lis 需要 推出 soc

在我們開發的過程中,經常會遇到需要我們判斷app進入後臺,或者切換到前臺的情況。比如我們想判斷app切換到前臺時,顯示一個解鎖界面,要求用戶輸入解鎖密碼才能繼續進行操作;我們想判斷app切換到後臺,記錄一下log;或者當用戶切換回前臺時,我們想刷新一下頁面的數據等等......

android裏面監聽app前後臺的方案很多(這還是得歸根於安卓提供了豐富的api和強大的架構支撐,呵呵~),比如可以通過ActivityManager提供的getRunningAppProcesses()獲取系統當前運行的app,從而判斷app是否處於前臺。或者通過監聽點擊Home鍵,判斷app是否回到了後臺。下面將針對筆者已知的幾種方案,進行對比分析。

方案一:利用ActivityManager的RunningAppProcessInfo類
ActivityManager在整個系統裏面起著非常重要的作用,主要為系統中運行著的activity交互提供接口,其中RunningAppProcessInfo類則封裝了正在運行著的進程信息,當然也包含了正在運行的app的包名,因此我們可以activitymanager.getRunningAppProcesses()獲取當前運行的app列表,對比自身的包名,來判斷本身app是否處於前臺運行。

這打斷一下,ActivityManager框架是Android系統十分重要的一部分,在以後有時間,筆者會好好學習整理ActivityManager框架的分析。

回到這裏,下面給出部分關鍵代碼。

 /**
     * App前後臺狀態
     */
    public boolean isForeground = false;
    @Override
    protected void onResume() {
        ......
        if (isForeground == false) {
            //由後臺切換到前臺
            isForeground = true;
        }
    }
 
    @Override
    protected
void onPause() { ...... if (!isAppOnForeground()) { //由前臺切換到後臺 isForeground = false; } } /** * 判斷app是否處於前臺 * * @return */ public boolean isAppOnForeground() { ActivityManager activityManager = (ActivityManager) getApplicationContext() .getSystemService(Context.ACTIVITY_SERVICE); String packageName = getApplicationContext().getPackageName(); /** * 獲取Android設備中所有正在運行的App */ List<RunningAppProcessInfo> appProcesses = activityManager .getRunningAppProcesses(); if (appProcesses == null) return false; for (RunningAppProcessInfo appProcess : appProcesses) { // The name of the process that this object is associated with. if (appProcess.processName.equals(packageName) && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { return true; } } return false; }

小結:通過ActivityManager來獲取當前運行的app列表,然後判斷我們的app是否處於前臺,能基本達到我們的預期需求。但如果將上面代碼放到每一個activity,或者activity基類裏面,這消耗還是挺大的。而且而且,ActivityManager通過.getRunningAppProcesses()獲取當前運行列表這個方法,在5.0以後已經被deprecated掉了....(心中萬馬奔騰...)

方案二:監聽Home鍵點擊

說起home鍵的監聽,也算是android裏面的一個梗。這看上去簡單的功能,實際上實現起來卻十分的曲折,這跟android系統的設計有很大的關系。當home鍵被點擊的時候,會發出一個系統廣播,在系統收到這個廣播以後,會在framework層做一系列操作將當前的app退到後臺,然後把事件消費掉不傳給應用層,所以這時候 onKeyDown事件也接收不到了..用官方的解釋就是——“Home key. This key is handled by the framework and is never delivered to applications.”。實際上這也是為了安全性的考慮,不然每家的app都監聽home鍵,然後禁掉響應,不都成了流氓軟件了。

官方不支持,可是這難不到我們萬能的攻城獅們的,畢竟有很多想我們正規的開發者,還是需要監聽home鍵來做一些如寫日誌之類的操作的。網上谷歌百度會有很多類似的解決方案,在這裏就不展開了。(不過這裏可以推薦一下)

小結:我們能監聽到home鍵點擊,當然就知道app處於前臺還是後臺了。但畢竟這個方案是基於官方不支持的前提下的,而且home鍵的監聽在很多設備都會有兼容性的問題,因此我們不大推薦這樣做。

方案三:利用ActivityLifecycleCallbacks監聽所有activity的生命周期

通過監聽所有activity的onStart、onStop調用,然後統計當前是不是所有的activity都調用了onStop,確實可以判斷app處於了後臺,不過讓我們重寫每一個activity的onStop,並加這段奇怪的代碼,實在不大優雅,即使在activity基類裏面統一寫,那天如果忘了或者不需要繼承基類的activity,就不大好了。

因此,這裏推薦一個新的接口ActivityLifecycleCallbacks,說新也不新,其實早在API 14 (android 4.0)就已經推出了。ActivityLifecycleCallbacks接口在Application類裏面,因此需要我們自己繼承Application,自定義一個MyApplication,然後註冊接口。ActivityLifecycleCallbacks為application提供了對所有activity生命周期的監聽,因此我們通過重寫ActivityLifecycleCallbacks的onActivityStarted和onActivityStopped方法,定義一個變量,來統計當前有幾個activity處於前臺。

  /**
     * 當前Acitity個數
     */
    private int activityAount = 0;
    
    @Override
    public void onCreate() {
        ......
        registerActivityLifecycleCallbacks(activityLifecycleCallbacks);
        ......
    }
 
    /**
     * Activity 生命周期監聽,用於監控app前後臺狀態切換
     */
    ActivityLifecycleCallbacks activityLifecycleCallbacks = new ActivityLifecycleCallbacks() {
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        }
 
        @Override
        public void onActivityStarted(Activity activity) {
//            if (activityAount == 0) {
//                //app回到前臺
//                isForeground = true;
//            }
            activityAount++;
        }
 
        @Override
        public void onActivityResumed(Activity activity) {
        }
        @Override
        public void onActivityPaused(Activity activity) {
        }
 
        @Override
        public void onActivityStopped(Activity activity) {
            activityAount--;
            if (activityAount == 0) {
                isForeground = false;
            }
        }
 
        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }
        @Override
        public void onActivityDestroyed(Activity activity) {
        }
    };

以上代碼寫在MyApplication裏面。怎麽樣,是不是很簡單快捷!而且準確無誤。

總結:
1、利用ActivityManager的RunningAppProcessInfo類,直接粗暴,官方摒棄,不推薦;
2、監聽Home鍵點擊,官方不支持,兼容性差,不穩定,不推薦;
3、利用ActivityLifecycleCallbacks監聽所有activity的生命周期,官方指定飲品,哦,不對,官方指定接口,大力推薦!我們舉一反三,利用ActivityLifecycleCallbacks監聽,我們還能控制我們的activity堆棧,甚至還可以在裏面做日誌統計...想想還是很強大的。

PS:雖則利用ActivityLifecycleCallbacks接口監聽的方案最優,但這畢竟是4.0以後的產品,因此對於4.0以下的,可以考慮增加方案一判斷。

Android 監聽APP進入後臺或切換到前臺方案對比