我的尝试
/**
* 判断应用是否是在后台
*/
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