检查Android应用程序是否在后台运行

本文翻译自:Checking if an Android application is running in the background

在后台,我的意思是用户当前看不到应用程序的任何活动?


#1楼

参考:https://stackoom.com/question/FNxW/检查Android应用程序是否在后台运行


#2楼

Idolon's answer is error prone and much more complicated althought repeatead here check android application is in foreground or not? Idolon的答案容易出错并且更复杂,尽管在这里重复检查Android应用程序是否在前台? and here Determining the current foreground application from a background task or service 在这里根据后台任务或服务确定当前的前台应用程序

There is a much more simpler approach: 有一种更简单的方法:

On a BaseActivity that all Activities extend: 所有活动都扩展BaseActivity上:

protected static boolean isVisible = false;

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


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

Whenever you need to check if any of your application activities is in foreground just check isVisible() ; 每当您需要检查是否有任何应用程序活动处于前台时,只需检查 isVisible()

To understand this approach check this answer of side-by-side activity lifecycle: Activity side-by-side lifecycle 要了解这种方法,请检查并排活动生命周期的以下答案: 活动并排生命周期


#3楼

In my activities onResume and onPause I write an isVisible boolean to SharedPrefences. 在onResume和onPause活动中,我为SharedPrefences写了一个isVisible布尔值。

    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
    Editor editor = sharedPrefs.edit();
    editor.putBoolean("visible", false);
    editor.commit();

And read it elsewhere when needed via, 并在需要时通过其他地方阅读,

    // Show a Toast Notification if App is not visible (ie in background. Not running, etc) 
    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
    if(!sharedPrefs.getBoolean("visible", true)){...}

Maybe not elegant, but it works for me... 也许不优雅,但对我有用。


#4楼

DO NOT USE THIS ANSWER 请勿使用此答案

user1269737's answer is the proper (Google/Android approved) way to do this . user1269737的答案是执行此操作的正确方法(已获得Google / Android批准) Go read their answer and give them a +1. 去阅读他们的答案,并给他们+1。

I'll leave my original answer here for posterity's sake. 为了后代的缘故,我将在这里保留原始答案。 This was the best available back in 2012, but now Android has proper support for this. 这是2012年提供的最好的软件,但现在Android对此已提供适当的支持。

Original answer 原始答案

The key is using ActivityLifecycleCallbacks (note that this requires Android API level 14 (Android 4.0)). 关键是使用ActivityLifecycleCallbacks (请注意,这需要Android API级别14(Android 4.0))。 Just check if the number of stopped activities is equal to the number of started activities. 只需检查已停止活动的数量是否等于已开始活动的数量即可。 If they're equal, your application is being backgrounded. 如果它们相等,则说明您的应用程序正在后台运行。 If there are more started activities, your application is still visible. 如果还有更多开始的活动,则您的应用程序仍然可见。 If there are more resumed than paused activities, your application is not only visible, but it's also in the foreground. 如果恢复的活动多于暂停的活动,则您的应用程序不仅可见,而且位于前台。 There are 3 main states that your activity can be in, then: visible and in the foreground, visible but not in the foreground, and not visible and not in the foreground (ie in the background). 然后,您的活动可以处于3个主要状态:可见和在前台,可见但不在前台,不可见且不在前台(即在后台)。

The really nice thing about this method is that it doesn't have the asynchronous issues getRunningTasks() does, but you also don't have to modify every Activity in your application to set/unset something in onResumed() / onPaused() . 关于此方法的真正getRunningTasks()是它没有getRunningTasks()的异步问题,但是您也不必修改应用程序中的每个Activity来设置或取消onResumed() / onPaused() It's just a few lines of code that's self contained, and it works throughout your whole application. 它仅包含几行代码,并且可以在整个应用程序中使用。 Plus, there are no funky permissions required either. 另外,也不需要时髦的权限。

MyLifecycleHandler.java: MyLifecycleHandler.java:

public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
    // I use four separate variables here. You can, of course, just use two and
    // increment/decrement them instead of using four and incrementing them all.
    private int resumed;
    private int paused;
    private int started;
    private int stopped;

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @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 onActivitySaveInstanceState(Activity activity, Bundle outState) {
    }

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

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

    // If you want a static function you can use to check if your application is
    // foreground/background, you can use the following:
    /*
    // Replace the four variables above with these four
    private static int resumed;
    private static int paused;
    private static int started;
    private static int stopped;

    // And these two public static functions
    public static boolean isApplicationVisible() {
        return started > stopped;
    }

    public static boolean isApplicationInForeground() {
        return resumed > paused;
    }
    */
}

MyApplication.java: MyApplication.java:

// Don't forget to add it to your manifest by doing
// <application android:name="your.package.MyApplication" ...
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        // Simply add the handler, and that's it! No need to add any code
        // to every activity. Everything is contained in MyLifecycleHandler
        // with just a few lines of code. Now *that's* nice.
        registerActivityLifecycleCallbacks(new MyLifecycleHandler());
    }
}

@Mewzer has asked some good questions about this method that I'd like to respond to in this answer for everyone: @Mewzer提出了有关此方法的一些好问题,我想在此答案中为所有人答复:

onStop() is not called in low memory situations; 在内存不足的情况下不会调用onStop() is that a problem here? 这是一个问题吗?

No. The docs for onStop() say: onStop()的文档说:

Note that this method may never be called, in low memory situations where the system does not have enough memory to keep your activity's process running after its onPause() method is called. 请注意,在内存不足的情况下(系统的内存不足,无法在调用其onPause()方法后保持活动的进程继续运行),可能永远不会调用此方法。

The key here is "keep your activity's process running ..." If this low memory situation is ever reached, your process is actually killed (not just your activity). 这里的关键是“让您的活动的进程保持运行 ……”如果曾经遇到这种内存不足的情况,您的进程实际上将被杀死(而不仅仅是活动)。 This means that this method of checking for backgrounded-ness is still valid because a) you can't check for backgrounding anyway if your process is killed, and b) if your process starts again (because a new activity is created), the member variables (whether static or not) for MyLifecycleHandler will be reset to 0 . 这意味着这种检查背景色的方法仍然有效,因为a)如果您的进程被杀死,则无论如何都无法检查背景,并且b)如果您的进程再次启动(因为创建了新活动),则该成员MyLifecycleHandler变量(无论是否为静态)将重置为0

Does this work for configuration changes? 这对配置更改有效吗?

By default, no. 默认情况下,没有。 You have to explicitly set configChanges=orientation|screensize ( | with anything else you want) in your manifest file and handle the configuration changes, or else your activity will be destroyed and recreated. 您必须在清单文件中显式设置configChanges=orientation|screensize|和其他所需的内容)并处理配置更改,否则您的活动将被破坏并重新创建。 If you do not set this, your activity's methods will be called in this order: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume . 如果未设置,则将按以下顺序调用活动的方法: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume As you can see, there is no overlap (normally, two activities overlap very briefly when switching between the two, which is how this backgrounding-detection method works). 如您所见,没有重叠(通常,在两个活动之间切换时,两个活动会非常短暂地重叠,这就是这种背景检测方法的工作原理)。 In order to get around this, you must set configChanges so that your activity is not destroyed. 为了解决这个问题,您必须设置configChanges以便不会破坏您的活动。 Fortunately, I've had to set configChanges already in all of my projects because it was undesirable for my entire activity to get destroyed on screen rotate/resize, so I've never found this to be problematic. 幸运的是,我已经在所有项目中都已经设置了configChanges ,因为我不希望整个活动都在屏幕旋转/调整大小时被破坏,所以我从来没有发现这是有问题的。 (thanks to dpimka for refreshing my memory on this and correcting me!) (感谢dpimka刷新了我的记忆并纠正了我!)

One note: 一注:

When I've said "background" here in this answer, I've meant "your app is no longer visible." 当我在此答案中说“背景”时,我的意思是“您的应用不再可见”。 Android activities can be visible yet not in the foreground (for example, if there's a transparent notification overlay). Android活动是可见的,但不是在前台(例如,如果有透明的通知覆盖)。 That's why I've updated this answer to reflect that. 这就是为什么我更新了此答案以反映这一点的原因。

It's important to know that Android has a weird limbo moment when switching activities where nothing is in the foreground . 重要的是要知道,Android在切换没有任何前景的活动时会有一个奇怪的困境。 For this reason, if you check if your application is in the foreground when switching between activities (in the same app), you'll be told you're not in the foreground (even though your app is still the active app and is visible). 因此,如果您在活动(在同一应用程序中)之间进行切换时检查应用程序是否在前台,则系统会告知您您不在前台(即使您的应用程序仍然是活动应用程序并且可见) )。

You can check if your app is in the foreground in your Activity 's onPause() method after super.onPause() . 您可以 super.onPause() 之后检查您的应用程序是否处于ActivityonPause()方法的super.onPause() Just remember the weird limbo state I just talked about. 只要记住我刚才谈到的怪异的边缘状态即可。

You can check if your app is visible (ie if it's not in the background) in your Activity 's onStop() method after super.onStop() . 您可以 super.onStop() 之后的 ActivityonStop()方法中检查您的应用是否可见(即,是否不在后台super.onStop()


#5楼

I did my own implementation of ActivityLifecycleCallbacks. 我做了自己的ActivityLifecycleCallbacks实现。 I'm using SherlockActivity, but for normal Activity class might work. 我正在使用SherlockActivity,但对于正常的Activity类可能会起作用。

First, I'm creating an interface that have all methods for track the activities lifecycle: 首先,我正在创建一个接口,该接口具有用于跟踪活动生命周期的所有方法:

public interface ActivityLifecycleCallbacks{
    public void onActivityStopped(Activity activity);
    public void onActivityStarted(Activity activity);
    public void onActivitySaveInstanceState(Activity activity, Bundle outState);
    public void onActivityResumed(Activity activity);
    public void onActivityPaused(Activity activity);
    public void onActivityDestroyed(Activity activity);
    public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}

Second, I implemented this interface in my Application's class: 其次,我在应用程序的类中实现了此接口:

public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{

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

    @Override
    public void onActivityStopped(Activity activity) {
        Log.i("Tracking Activity Stopped", activity.getLocalClassName());

    }

    @Override
    public void onActivityStarted(Activity activity) {
        Log.i("Tracking Activity Started", activity.getLocalClassName());

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
    }

    @Override
    public void onActivityResumed(Activity activity) {
        Log.i("Tracking Activity Resumed", activity.getLocalClassName());
    }

    @Override
    public void onActivityPaused(Activity activity) {
        Log.i("Tracking Activity Paused", activity.getLocalClassName());
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        Log.i("Tracking Activity Created", activity.getLocalClassName());
    }
}

Third, I'm creating a class that extends from SherlockActivity: 第三,我正在创建一个继承自SherlockActivity的类:

public class MySherlockActivity extends SherlockActivity {

    protected MyApplication nMyApplication;

    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        nMyApplication = (MyApplication) getApplication();
        nMyApplication.onActivityCreated(this, savedInstanceState);
    }

    protected void onResume() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityResumed(this);
        super.onResume();

    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityPaused(this);
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityDestroyed(this);
        super.onDestroy();
    }

    @Override
    protected void onStart() {
        nMyApplication.onActivityStarted(this);
        super.onStart();
    }

    @Override
    protected void onStop() {
        nMyApplication.onActivityStopped(this);
        super.onStop();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        nMyApplication.onActivitySaveInstanceState(this, outState);
        super.onSaveInstanceState(outState);
    }   
}

Fourth, all class that extend from SherlockActivity, I replaced for MySherlockActivity: 第四,所有从SherlockActivity扩展的类,我都替换为MySherlockActivity:

public class MainActivity extends MySherlockActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

}

Now, in the logcat you will see the logs programmed in the Interface implementation made in MyApplication. 现在,在logcat中,您将看到My​​Application中实现的Interface实现中编程的日志。


#6楼

I would like to recommend you to use another way to do this. 我建议您使用另一种方法来执行此操作。

I guess you want to show start up screen while the program is starting, if it is already running in backend, don't show it. 我想您想在程序启动时显示启动屏幕,如果它已经在后端运行,请不要显示它。

Your application can continuously write current time to a specific file. 您的应用程序可以将当前时间连续写入特定文件。 While your application is starting, check the last timestamp, if current_time-last_time>the time range your specified for writing the latest time, it means your application is stopped, either killed by system or user himself. 在您的应用程序启动时,请检查最后一个时间戳,如果current_time-last_time>您为写入最新时间而指定的时间范围,则意味着您的应用程序已停止,已被系统或用户杀死。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值