检查Android应用程序是否在前台?
我经历了很多关于这个问题的答案。但是所有关于单个活动。如何检查整个应用程序是否在前台运行?
我不明白你想要什么,但你可以通过ActivityManager.getRunningAppProcesses()
调用来检测当前的前景/后台应用程序。
就像是,
class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> { @Override protected Boolean doInBackground(Context... params) { final Context context = params[0].getApplicationContext(); return isAppOnForeground(context); } private boolean isAppOnForeground(Context context) { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); if (appProcesses == null) { return false; } final String packageName = context.getPackageName(); for (RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) { return true; } } return false; } } // Use like this: boolean foregroud = new ForegroundCheckTask().execute(context).get();
也让我知道如果我误解..
更新:看看这个SO问题从后台任务或服务确定当前的前台应用程序更多信息..
谢谢..
@ user370305的回答很容易出错, 并被Android操作系统开发人员拒之门外(查https://groups.google.com/forum/#!msg/android-developers/zH-2bovZSLg/L2YM8Z1N-HwJ )
有一个更简单的方法:
在所有活动延伸的基础活动上 :
protected static boolean isVisible = false; @Override public void onResume() { super.onResume(); setVisible(true); } @Override public void onPause() { super.onPause(); setVisible(false); }
每当你需要检查你的应用程序活动是否在前台时,只需检查 isVisible();
为了理解这种方法,请检查并排活动生命周期的这个答案: 活动并行生命周期
到目前为止,我发现的最好的但并不被弃用的方法如下:
@Override public boolean foregrounded() { ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo(); ActivityManager.getMyMemoryState(appProcessInfo); return (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE) }
它只适用于SDK 16+。
编辑 :
我从解决scheme中删除了以下代码:
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); // App is foreground, but screen is locked, so show notification return km.inKeyguardRestrictedInputMode();
因为如果屏幕locking,则不会收到通知。 我看了一下这个框架,其目的并不完全清楚。 我会删除它。 检查进程信息状态就足够了:-)
我已经尝试过运行过程中的包filter。 但是这很奇怪。 相反,我尝试新的解决scheme,这完美的工作。 我已经检查了很多次,并通过这个模块获得了完美的结果。
private int numRunningActivities = 0; public void onCreate() { super.onCreate(); this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityStarted(Activity activity) { numRunningActivities++; if (numRunningActivities == 1) { LogUtils.d("APPLICATION", "APP IN FOREGROUND"); } } @Override public void onActivityStopped(Activity activity) { numRunningActivities--; if (numRunningActivities == 0) { Log.e("", "App is in BACKGROUND") } } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } }); }
检查应用程序是否在后台或前台。 如果应用程序在后台,此方法将返回true。
首先添加GET_TASKS权限到您的AndroidManifest.xml
private boolean isAppIsInBackground(Context context) { boolean isInBackground = true; ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) { List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses(); for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) { if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { for (String activeProcess : processInfo.pkgList) { if (activeProcess.equals(context.getPackageName())) { isInBackground = false; } } } } } else { List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1); ComponentName componentInfo = taskInfo.get(0).topActivity; if (componentInfo.getPackageName().equals(context.getPackageName())) { isInBackground = false; } } return isInBackground; }
我已经find了一个简单的解决scheme,通过创build一个基本的活动类,你必须扩展你所有的活动类:
public class BaseActivity extends ActionBarActivity { @Override protected void onResume() { ApplicationStateChecker.view_resumed(this); super.onResume(); } @Override protected void onStop() { ApplicationStateChecker.view_stopped(this); super.onStop(); } @Override protected void onPause() { ApplicationStateChecker.view_paused(this); super.onPause(); } }
ApplicationStateChecker类:
public class ApplicationStateChecker { private static final String _pause_string = "paused"; private static final String _resume_string = "resumed"; private static String _view_lastState; private static boolean _from_background = true; public static void view_paused(Activity activity){ _view_lastState = _pause_string; } public static void view_stopped(Activity activity){ if ( _view_lastState.equals(_pause_string) ){ //if stop called and last event was pause then app is brought to background _from_background = true; } //if } public static void view_resumed(Activity activity){ if ( _from_background ) { //Do your stuff here , app is brought to foreground } //if _from_background = false; _view_lastState = _resume_string; }
没有全局callback,但是对于每个活动,它都是onStop()。 你不需要搞乱一个atomic int。 只要有一个全局int与启动活动的数量,在每一个活动增加onStart()并减less它在onStop()。
public class BaseActivity extends ActionBarActivity { public static int count = 0; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void onStart() { super.onStart(); count = count + 1; Log.d(TAG, "onStart" + count); if (count == 1) { Toast.makeText(getApplicationContext(), "online", Toast.LENGTH_SHORT).show(); } } protected void onStop() { super.onStop(); count = count - 1; if (count == 0) { Toast.makeText(getApplicationContext(), "offline", Toast.LENGTH_SHORT).show(); } } }
cesards的答案是正确的,但只适用于API> 15.对于较低的API版本,我决定使用getRunningTasks()
方法:
private boolean isAppInForeground(Context context) { if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE); ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0); String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName(); return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase()); } else { ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo(); ActivityManager.getMyMemoryState(appProcessInfo); if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE) { return true; } KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); // App is foreground, but screen is locked, so show notification return km.inKeyguardRestrictedInputMode(); } }
请让我知道它是否适用于你们。
在Application类中尝试ActivityLifecycleCallbacks。
基于getRunningTasks()的解决scheme在最近的Android版本中都不适用, getRunningTasks()在API级别21中被弃用。即使它仍然被使用,它也不会返回足够的信息来确定该应用是否在前台。
相反,扩展Application类并使用Application.ActivityLifecycleCallbacks来跟踪应用程序可见性状态。
public class MyApplication extends Application { static final String APP_STATE_FOREGROUND = "com.xxx.appstate.FOREGROUND"; static final String APP_STATE_BACKGROUND = "com.xxx.appstate.BACKGROUND"; private static int m_foreground = -1; private Handler m_handler = new Handler(); private Runnable m_guard; public static boolean isForeground() { return m_foreground == 1; } @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { if(m_guard != null) { m_handler.removeCallbacks(m_guard); m_guard = null; } if(m_foreground == 1) return; m_foreground = 1; sendBroadcast(new Intent(APP_STATE_FOREGROUND)); } @Override public void onActivityPaused(Activity activity) { if(m_foreground == 0) return; /* * Use a 400ms guard to protect against jitter * when switching between two activities * in the same app */ m_guard = new Runnable() { @Override public void run() { if(m_foreground == 1) { m_foreground = 0; sendBroadcast(new Intent(APP_STATE_BACKGROUND)); } } }; m_handler.postDelayed(m_guard, 400); } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { } }); } }
使用400ms保护计时器消除了在同一应用中的活动之间切换时错误地检测到背景状态。 后台/前台状态可以随时查询,使用:
MyApplication.isForeground();
如果一个类对状态转换感兴趣,也可以监听广播事件:
private static IntentFilter m_appStateFilter; static { m_appStateFilter = new IntentFilter(); m_appStateFilter.addAction(MyApplication.APP_STATE_FOREGROUND); m_appStateFilter.addAction(MyApplication.APP_STATE_BACKGROUND); } private BroadcastReceiver m_appStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(MyApplication.APP_STATE_FOREGROUND)) { /* application entered foreground */ } else if (action.equals(MyApplication.APP_STATE_BACKGROUND)) { /* application entered background */ } } }; registerReceiver(m_appStateReceiver, m_appStateFilter);
以下是最新Android SDK的解决scheme。
String PackageName = context.getPackageName(); ActivityManager manager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE); ComponentName componentInfo; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { List<ActivityManager.AppTask> tasks = manager.getAppTasks(); componentInfo = tasks.get(0).getTaskInfo().topActivity; } else { List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1); componentInfo = tasks.get(0).topActivity; } if (componentInfo.getPackageName().equals(PackageName)) return true; return false;
希望这有助于,谢谢。