1. 程式人生 > >判斷你的應用在前臺還是在後臺

判斷你的應用在前臺還是在後臺

keyword 優化 rdm span sap ber callback handle tex

我的嘗試

/**
     * 判斷應用是否是在後臺
     */
    public static boolean isBackground(Context context) {
        ActivityManager activityManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(KEYGUARD_SERVICE);

        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager
                .getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (TextUtils.equals(appProcess.processName, context.getPackageName())) {
                return appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
            }
        }
        return false;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

一開始我用這個方法用來判斷手機是否處於後臺狀態,如果應用處於後臺的話,就停止應用程序中的音樂播放,但是卻發現,點擊 Home 鍵讓應用退到後臺並不會讓音樂停止播放,後來發現如果應用正在播放音樂的話,此時點擊 Home 鍵應用並不會進入後臺狀態( ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND ),而是進入了一個 ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE 的狀態, 這個狀態正是系統提供的應用後臺播放應用的狀態,好了,我們繼續在原來的代碼上進行完善:

/**
     * 判斷應用是否是在後臺
     */
    public static boolean isBackground(Context context) {
        ActivityManager activityManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(KEYGUARD_SERVICE);

        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager
                .getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (TextUtils.equals(appProcess.processName, context.getPackageName())) {
                return (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND || appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE);
            }
        }
        return false;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

這樣即使應用在播放應用的時候點擊 Home 鍵也可以認為此時處於後臺狀態,但是此時依然會出現判斷應用是否在後臺不準確的情況,我們繼續優化原來的代碼。

/**
     * 判斷應用是否是在後臺
     */
    public static boolean isBackground(Context context) {
        ActivityManager activityManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(KEYGUARD_SERVICE);

        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager
                .getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (TextUtils.equals(appProcess.processName, context.getPackageName())) {
                boolean isBackground = (appProcess.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE);
                boolean isLockedState = keyguardManager.inKeyguardRestrictedInputMode();
                return isBackground || isLockedState;
            }
        }
        return false;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

上面這個方法通過監測應用進程是否處於前臺狀態,是否可見,手機是否鎖屏來判斷應用是否處於前臺,如果這些情況有任一條達成的話就表明應用沒有處於前臺狀態,這個方法在大部分測試機上都沒有發現異常,但是我卻在原生的 Nexus 5 手機上發現當當棧中的Activiy只有一個 Activity的時候,例如:應用啟動,SplashActivity啟動LoginActivity後,關閉SplashActivity,此時棧中就只生剩下了LoginActivity,此時,無論是點擊返回鍵退出、點擊 Home 鍵退到後臺甚至點擊右側的多進程按鍵,此時的appProcess.importance 的都為 ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND,這樣就徹底宣告了判斷 appProcess.importance方法的失敗。

最終用法

繼承 Application.ActivityLifecycleCallbacks 寫一個自己的 ActivityLifecycleCallbacks:

public class MyLifecycleHandler implements Application.ActivityLifecycleCallbacks {
    private static int resumed;
    private static int paused;
    private static int started;
    private static int stopped;

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    }

    @Override
    public void onActivityStarted(Activity activity) {
        ++started;
    }

    @Override
    public void onActivityResumed(Activity activity) {
        ++resumed;
    }

    @Override
    public void onActivityPaused(Activity activity) {
        ++paused;
        android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
    }

    @Override
    public void onActivityStopped(Activity activity) {
        ++stopped;
        android.util.Log.w("test", "application is visible: " + (started > stopped));
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    }

    public static boolean isApplicationVisible() {
        return started > stopped;
    }

    public static boolean isApplicationInForeground() {
    // 當所有 Activity 的狀態中處於 resumed 的大於 paused 狀態的,即可認為有Activity處於前臺狀態中 
        return resumed > paused;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

然後在自己定義的 Application 中的 onCreate() 方法中註冊該 ActivityLifecycleCallbacks:

registerActivityLifecycleCallbacks(new MyLifecycleHandler());
  • 1
  • 1

這樣的話我們就可以在自己定義的 ActivityLifecycleCallbacks 中監控自己應用中的所有的 Activity 的狀態,通過 MyLifecycleHandler.isApplicationInForeground() 方法即可判斷應用此時一定處於前臺狀態中,反之,則是處於”後臺狀態”。

以上就是我對於當前應用是處於前臺還是後臺的判斷,無論大家是發現BUG和改進,還是有其它更好的辦法,歡迎前來討論!

需要註意:ActivityLifecycleCallbacks是在 API 14 即 Android 4.0加入的。

參考鏈接

http://stackoverflow.com/questions/3667022/checking-if-an-android-application-is-running-in-the-background/13809991#13809991
http://stackoverflow.com/questions/3667022/checking-if-an-android-application-is-running-in-the-background/5862048#5862048
https://segmentfault.com/q/1010000000687701
http://www.dewen.net.cn/q/10250/android%E7%B3%BB%E7%BB%9F%E8%BF%9B%E7%A8%8B%E9%87%8D%E8%A6%81%E7%AD%89%E7%BA%A7%E4%B8%ADIMPORTANCE_BACKGROUND%E5%92%8CIMPORTANCE_PERCEPTIBLE%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%EF%BC%9F

判斷你的應用在前臺還是在後臺