检查 android 应用程序是否在前台?

对于这个问题,我回答了很多。但这都是单一的活动。.如何检查整个应用程序是否在前台运行?

171532 次浏览

我不明白你想要什么,但你可以检测目前的前景/后台应用程序与 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();

Also let me know if I misunderstand..

更新: 更多信息请看这个 SO 问题 从后台任务或服务确定当前前台应用程序. 。

谢谢。

@ user370305的答案是容易出错和 安卓操作系统开发人员的反对(检查 https://groups.google.com/forum/#!msg/android-developers/zH-2bovZSLg/L2YM8Z1N-HwJ)

还有一个更简单的方法:

所有活动扩展的 BaseActivity上:

protected static boolean isVisible = false;


@Override
public void onResume() {
super.onResume();
setVisible(true);
}


@Override
public void onPause() {
super.onPause();
setVisible(false);
}

如果需要检查应用程序活动是否在前台,只需检查 isVisible();

To understand this approach check this answer of side-by-side activity lifecycle: 活动并行生命周期

我已经找到了一个简单的解决方案,通过创建一个基本的活动类,您必须从这里扩展所有的活动类:

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 class :

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;
}

对此没有全局回调,但是对于每个活动它都是 onStop ()。你不需要搞乱原子整型。只需要有一个包含已启动活动数量的全局整数,在每个活动中,该整数在 onStart ()中递增,在 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();


}
}




}

检查应用程序是在后台还是在前台。如果应用程序在后台,这个方法将返回 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;
}

在应用程序类中尝试 ActivityLificycleCallback。

我试过用包过滤器从运行过程。但这很奇怪。相反,我尝试了新的解决方案,这个工作完美。我已经检查了很多次,通过这个模块得到了很好的结果。

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) {
}
});
}

Update Oct 2020: Checkout the Lifecycle extensions based solutions on this thread. The approach seems to be working, it's more elegant and modern.


到目前为止,我找到了一种最干净利落的方法来做到这一点,具体如下:

@Override
public boolean foregrounded() {
ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
ActivityManager.getMyMemoryState(appProcessInfo);
return (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
}

它只适用于 SDK 16 + 。

EDIT:

我从解决方案中删除了以下代码:

KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
// App is foreground, but screen is locked, so show notification
return km.inKeyguardRestrictedInputMode();

since that makes not getting the notifications if the screen locked. I had a look to the framework and the purpose of this is not entirely clear. I'd remove it. Checking the process info state would be enough :-)

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();
}
}

如果对你们有用,请告诉我。

在最近的 Android 版本中,基于 GetRunningTasks ()的解决方案都不能正常工作,在 API 级别21中,GetRunningTasks ()已被弃用。即使它仍在使用,它也不会返回足够的信息来确定应用程序是否在前台。

Instead extend the Application class and use Application.ActivityLifecycleCallbacks to track application visibility state.

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 的更新解决方案。

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;

希望这个能帮上忙,谢谢。

Below solution works from API level 14+

背景 Component Callbacks2ー查看文档并不能100% 清楚地了解您将如何使用它。但是,仔细观察一下,您会发现 onTrimMemory 方法传递了一个标志。这些标志通常与内存可用性有关,但我们关心的是 TRIM _ MEMORY _ UI _ HIDDEN。通过检查 UI 是否隐藏,我们可以假设应用程序现在在后台。不是很明显,但应该有用。

前景化 ActivityLificycleCallback ー我们可以通过重写 onActivityResumed 并跟踪当前应用程序状态(Foreground/Backback)来使用它来检测前台。

Create our interface that will be implemented by a custom Application class

interface LifecycleDelegate {
fun onAppBackgrounded()
fun onAppForegrounded()
}

创建一个类,该类将实现 ActivityLificycleCallback 和 Component entCallbacks2,并覆盖 onActivityResumed 和 onTrimMemory 方法

// Take an instance of our lifecycleHandler as a constructor parameter
class AppLifecycleHandler(private val lifecycleDelegate: LifecycleDelegate)
: Application.ActivityLifecycleCallbacks, ComponentCallbacks2 // <-- Implement these
{
private var appInForeground = false


// Override from Application.ActivityLifecycleCallbacks
override fun onActivityResumed(p0: Activity?) {
if (!appInForeground) {
appInForeground = true
lifecycleDelegate.onAppForegrounded()
}
}


// Override from ComponentCallbacks2
override fun onTrimMemory(level: Int) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// lifecycleDelegate instance was passed in on the constructor
lifecycleDelegate.onAppBackgrounded()
}
}
}

现在我们需要做的就是让我们的自定义 Application 类实现我们的 LificycleGenerate 接口和注册。

class App : Application(), LifeCycleDelegate {


override fun onCreate() {
super.onCreate()
val lifeCycleHandler = AppLifecycleHandler(this)
registerLifecycleHandler(lifeCycleHandler)
}


override fun onAppBackgrounded() {
Log.d("Awww", "App in background")
}


override fun onAppForegrounded() {
Log.d("Yeeey", "App in foreground")
}


private fun registerLifecycleHandler(lifeCycleHandler: AppLifecycleHandler) {
registerActivityLifecycleCallbacks(lifeCycleHandler)
registerComponentCallbacks(lifeCycleHandler)
}


}

在清单中设置 CustomApplicationClass

<application
android:name=".App"

您可以使用 ProcessLifecycleOwneronStartonStop事件的整个应用程序进程设置一个侦听器。为此,让应用程序类实现 LifecycleObserver接口,并将 onStartonStop的一些注释添加到前景和背景方法中。

class ArchLifecycleApp : Application(), LifecycleObserver {


override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}


@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
Log.d("Awww", "App in background")
}


@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
Log.d("Yeeey", "App in foreground")
}


}

通过新的 Android 生命周期架构扩展,我们可以轻松实现这一点。

只要确保在 build.gradle 文件中拉出这个依赖项:

dependencies {
implementation "android.arch.lifecycle:extensions:1.1.0"
}

然后在应用程序类中使用:

class ArchLifecycleApp : Application(), LifecycleObserver {


override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}


@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
Log.d("MyApp", "App in background")
}


@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
Log.d("MyApp", "App in foreground")
}
}

最后,用以下方法更新 AndroidManifest.xml 文件:

<application
android:name=".ArchLifecycleApp"
//Your extra code
....>
</application>

现在,每次应用程序转到前台或后台时,我们都会收到与声明的两个方法相关联的日志。

更新: @OnLifecycleEvent已经去除杂质

@ OnLificycleEvent 注释需要使用代码生成或 reflection, which should be avoided. Use DefaultLifecycleObserver or LifecycleEventObserver instead. 有关更多信息,请参见 < a href = “ https://stackoverflow. com/a/70808707/1972597”> 本示例

在 Android 19中,你可以在 Application 类的 onCreate ()中注册一个应用程序生命周期回调,如下所示:

@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new AppLifecycleCallback());
}

应用生命周期回调看起来像这样:

class AppLifecycleCallback implements Application.ActivityLifecycleCallbacks {
private int numStarted = 0;


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


}


@Override
public void onActivityStarted(Activity activity) {
if (numStarted == 0) {
//app went to foreground
}
numStarted++;
}


@Override
public void onActivityResumed(Activity activity) {


}


@Override
public void onActivityPaused(Activity activity) {


}


@Override
public void onActivityStopped(Activity activity) {
numStarted--;
if (numStarted == 0) {
// app went to background
}
}


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


}


@Override
public void onActivityDestroyed(Activity activity) {


}
}