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

时间:2021-09-25 20:51:45

By background, I mean none of the application's activities are currently visible to the user?

通过后台,我的意思是,应用程序的所有活动都不可见于用户?

27 个解决方案

#1


362  

There are few ways to detect whether your application is running in the background, but only one of them is completely reliable:

有几种方法可以检测您的应用程序是否在后台运行,但是其中只有一个是完全可靠的:

  1. The right solution (credits go to Dan, CommonsWare and NeTeInStEiN)
    Track visibility of your application by yourself using Activity.onPause, Activity.onResume methods. Store "visibility" status in some other class. Good choices are your own implementation of the Application or a Service (there are also a few variations of this solution if you'd like to check activity visibility from the service).
     
    Example
    Implement custom Application class (note the isActivityVisible() static method):

    正确的解决方案(归功于Dan, CommonsWare和NeTeInStEiN)使用活动来跟踪应用程序的可见性。onPause,活动。onResume方法。在其他类中存储“可见性”状态。好的选择是您自己的应用程序或服务的实现(如果您想从服务中查看活动可见性,也有一些不同的解决方案)。示例实现自定义应用程序类(注意isActivityVisible()静态方法):

    public class MyApplication extends Application {
    
      public static boolean isActivityVisible() {
        return activityVisible;
      }  
    
      public static void activityResumed() {
        activityVisible = true;
      }
    
      public static void activityPaused() {
        activityVisible = false;
      }
    
      private static boolean activityVisible;
    }
    

    Register your application class in AndroidManifest.xml:

    在AndroidManifest.xml中注册您的应用程序类。

    <application
        android:name="your.app.package.MyApplication"
        android:icon="@drawable/icon"
        android:label="@string/app_name" >
    

    Add onPause and onResume to every Activity in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended from MapActivity/ListActivity etc. you still need to write the following by hand):

    将onPause和onResume添加到项目中的每一个活动中(如果您愿意,您可以为您的活动创建一个共同的祖先,但是如果您的活动已经从MapActivity/ListActivity等扩展了,您仍然需要手工编写以下内容):

    @Override
    protected void onResume() {
      super.onResume();
      MyApplication.activityResumed();
    }
    
    @Override
    protected void onPause() {
      super.onPause();
      MyApplication.activityPaused();
    }
    

     
    Update
    ActivityLifecycleCallbacks were added in API level 14 (Android 4.0). You can use them to track whether an activity of your application is currently visible to the user. Check Cornstalks' answer below for the details.

    更新ActivityLifecycleCallbacks在API级别14 (Android 4.0)中添加。您可以使用它们来跟踪应用程序的活动是否对用户可见。查看玉米秸秆的答案,了解详情。

  2. The wrong one
    I used to suggest the following solution:

    我曾经提出了一个错误的建议:

    You can detect currently foreground/background application with ActivityManager.getRunningAppProcesses() which returns a list of RunningAppProcessInfo records. To determine if your application is on the foreground check RunningAppProcessInfo.importance field for equality to RunningAppProcessInfo.IMPORTANCE_FOREGROUND while RunningAppProcessInfo.processName is equal to your application package name.

    您可以使用activitymanager . getrunningappprocess()来检测当前的前台/后台应用程序,该应用程序返回RunningAppProcessInfo记录的列表。确定您的应用程序是否在前台检查RunningAppProcessInfo。重要字段,以实现对RunningAppProcessInfo的平等。IMPORTANCE_FOREGROUND RunningAppProcessInfo。processName等于您的应用程序包名。

    Also if you call ActivityManager.getRunningAppProcesses() from your application UI thread it will return importance IMPORTANCE_FOREGROUND for your task no matter whether it is actually in the foreground or not. Call it in the background thread (for example via AsyncTask) and it will return correct results.

    如果您调用activitymanager . getrunningappprocess()从您的应用程序UI线程中,它将返回您的任务的重要性,无论它是否在前台。在后台线程(例如通过AsyncTask)调用它,它将返回正确的结果。

    While this solution may work (and it indeed works most of the time) I strongly recommend to refrain from using it. And here's why. As Dianne Hackborn wrote:

    虽然这个解决方案可能起作用(而且确实在大多数情况下是有效的),但我强烈建议不要使用它。这是为什么。Dianne Hackborn写道:

    These APIs are not there for applications to base their UI flow on, but to do things like show the user the running apps, or a task manager, or such.

    这些api并不存在于应用程序以建立其UI流的基础上,而是用于向用户显示正在运行的应用程序,或任务管理器之类的东西。

    Yes there is a list kept in memory for these things. However, it is off in another process, managed by threads running separately from yours, and not something you can count on (a) seeing in time to make the correct decision or (b) have a consistent picture by the time you return. Plus the decision about what the "next" activity to go to is always done at the point where the switch is to happen, and it is not until that exact point (where the activity state is briefly locked down to do the switch) that we actually know for sure what the next thing will be.

    是的,有一个清单保存在内存中。但是,它在另一个进程中,由与您的线程分开运行的线程管理,而不是您可以指望(a)及时做出正确的决定或(b)在您返回时具有一致的图像。加上什么“下一个”活动的决定去总是在点开关在哪里发生,直到,确切点(活动状态是暂时锁定开关),实际上我们知道接下来会是什么。

    And the implementation and global behavior here is not guaranteed to remain the same in the future.

    这里的实现和全球行为在未来不保证保持不变。

    I wish I had read this before I posted an answer on the SO, but hopefully it's not too late to admit my error.

    我希望在我把答案写在上面之前,我已经读过这篇文章,但我希望现在承认我的错误还为时不晚。

  3. Another wrong solution
    Droid-Fu library mentioned in one of the answers uses ActivityManager.getRunningTasks for its isApplicationBroughtToBackground method. See Dianne's comment above and don't use that method either.

    另一个错误的解决方案Droid-Fu库在其中一个答案中使用了ActivityManager。为其isApplicationBroughtToBackground方法进行了getRunningTasks。请参见上面的Dianne的评论,也不要使用那个方法。

#2


245  

The key is using ActivityLifecycleCallbacks (note that this requires Android API level 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 (i.e. in the background).

关键是使用ActivityLifecycleCallbacks(请注意,这需要Android API级别14 (Android 4.0))。只要检查停止活动的数量是否等于开始活动的数量。如果它们是相等的,那么你的应用程序就被搁置了。如果有更多的启动活动,您的应用程序仍然可见。如果有比暂停的活动更多的恢复,您的应用程序不仅可见,而且还在前台。有三个主要的状态,你的活动可以在,然后:可见和在前景,可见,但不是在前景,和不可见,而不是在前景(即在背景中)。

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(). 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.

这种方法的真正好处是它没有异步问题getRunningTasks(),但是您也不必修改应用程序中的每一个活动来设置/取消on重启()/ on暂停()的内容。它只是包含了几行代码,在整个应用程序中都可以使用。另外,也不需要任何古怪的权限。

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; is that a problem here?

在低内存情况下不调用onStop();这是个问题吗?

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.

这里的关键是“保持你的活动进程运行…”如果这种低内存的情况达到了,那么您的进程实际上已经被杀死了(而不仅仅是您的活动)。这意味着这种方法检查backgrounded-ness仍然有效,因为)你不能检查后台处理无论如何如果你的过程是死亡,和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. 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. 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. 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. (thanks to dpimka for refreshing my memory on this and correcting me!)

默认情况下,没有。您必须在manifest文件中显式地设置configChanges=orientation|屏幕大小(您想要的其他任何东西),并处理配置更改,否则您的活动将被销毁并重新创建。如果你不设置这个,你的活动的方法将按这个顺序被调用:onCreate -> onStart -> onResume ->(现在旋转)-> onPause -> onStop -> onDestroy -> onStart -> onStart -> onResume。正如您所看到的,没有重叠(通常情况下,两个活动在两者之间切换时非常短暂,这就是这种背景探测方法的工作原理)。为了解决这个问题,您必须设置configChanges,这样您的活动就不会被破坏。幸运的是,我已经在所有的项目中设置了configChanges,因为我的整个活动都不希望在屏幕上被破坏,所以我从来没有发现这是有问题的。(多亏了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). That's why I've updated this answer to reflect that.

当我在这个答案里说“背景”时,我的意思是“你的应用不再可见了”。Android的活动在前景中是可见的(例如,如果有透明的通知覆盖)。这就是为什么我更新了这个答案来反映这一点。

It's important to know that Android has a weird limbo moment when switching activities where nothing is in the foreground. 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).

很重要的一点是,知道Android有一个奇怪的不确定的时刻,当切换活动时,没有任何东西在前台。基于这个原因,如果你检查你的应用程序是否在前台切换(在同一应用程序中),你会被告知你不在前台(即使你的应用程序仍然是活动的app,并且是可见的)。

You can check if your app is in the foreground in your Activity's onPause() method after super.onPause(). Just remember the weird limbo state I just talked about.

你可以检查你的应用程序是否在你的Activity的onPause()方法中。onPause()方法。只记得我刚才说过的那种奇怪的不稳定状态。

You can check if your app is visible (i.e. if it's not in the background) in your Activity's onStop() method after super.onStop().

您可以检查您的应用程序是否可见(如果它不在后台),在您的活动的onStop()方法之后。onStop()。

#3


16  

Idolon's answer is error prone and much more complicated althought repeatead here check android application is in foreground or not? and here Determining the current foreground application from a background task or service

Idolon的答案是容易出错的,更复杂的althought repeatead在这里检查android应用是否在前台?在这里,从后台任务或服务中确定当前的前台应用程序。

There is a much more simpler approach:

有一种更简单的方法:

On a BaseActivity that all Activities extend:

在所有活动扩展的基础活动中:

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

要理解这种方法,请检查并行活动生命周期的这个答案:活动并行生命周期。

#4


9  

I tried the recommended solution that uses Application.ActivityLifecycleCallbacks and many others, but they didn't work as expected. Thanks to Sarge, I came up with a pretty easy and straightforward solution that I am describing below.

我尝试了使用应用程序的推荐解决方案。ActivityLifecycleCallbacks和其他许多人,但他们没有像预期的那样工作。多亏了Sarge,我想出了一个非常简单明了的解决方案。

They key of the solution is the fact of understanding that if we have ActivityA and ActivityB, and we call ActivityB from ActivityA (and not call ActivityA.finish), then ActivityB's onStart() will be called before ActivityA onStop().

解决方案的关键是要了解,如果我们有ActivityA和ActivityB,我们从ActivityA(不叫ActivityA.finish)中调用ActivityB,那么ActivityB的onStart()将在ActivityA onStop()之前被调用。

That's also the main difference between onStop() and onPause() that none did mention in the articles I read.

这也是onStop()和onPause()之间的主要区别,在我阅读的文章中没有提到。

So based on this Activity's Lifecycle behavior, you can simply count how many times did onStart() and onPause() got called in your program. Note that for each Activity of your program, you must override onStart() and onStop(), in order to increment/decrement the static variable used for counting. Below is the code implementing this logic. Note that I am using a class that extends Application, so dont forget to declare on Manifest.xml inside Application tag: android:name=".Utilities", although it can be implemented using a simple custom class too.

因此,基于该活动的生命周期行为,您可以简单地计算onStart()和onPause()在您的程序中调用了多少次。注意,对于程序的每个活动,必须覆盖onStart()和onStop(),以增加/减少用于计数的静态变量。下面是实现该逻辑的代码。注意,我正在使用一个扩展应用程序的类,所以不要忘记在Manifest上声明。应用程序标签:android:name="。尽管它也可以使用简单的自定义类实现。

public class Utilities extends Application
{
    private static int stateCounter;

    public void onCreate()
    {
        super.onCreate();
        stateCounter = 0;
    }

    /**
     * @return true if application is on background
     * */
    public static boolean isApplicationOnBackground()
    {
        return stateCounter == 0;
    }

    //to be called on each Activity onStart()
    public static void activityStarted()
    {
        stateCounter++;
    }

    //to be called on each Activity onStop()
    public static void activityStopped()
    {
        stateCounter--;
    }
}

Now on each Activity of our program, we should override onStart() and onStop() and increment/decrement as shown below:

现在,在我们的程序的每个活动中,我们应该覆盖onStart()和onStop()和递增/递减,如下所示:

@Override
public void onStart()
{
    super.onStart();
    Utilities.activityStarted();
}

@Override
public void onStop()
{
    Utilities.activityStopped();
    if(Utilities.isApplicationOnBackground())
    {
        //you should want to check here if your application is on background
    }
    super.onStop();
}

With this logic, there are 2 possible cases:

有了这个逻辑,有两种可能的情况:

  1. stateCounter = 0 : The number of stopped is equal with the number of started Activities, which means that the application is running on the background.
  2. stateCounter = 0:停止的数量与启动活动的数量相等,这意味着应用程序在后台运行。
  3. stateCounter > 0 : The number of started is bigger than the number of stopped, which means that the application is running on the foreground.
  4. stateCounter > 0:开始的数量大于停止的数量,这意味着应用程序在前台运行。

Notice: stateCounter < 0 would mean that there are more stopped Activities rather than started, which is impossible. If you encounter this case, then it means that you are not increasing/decreasing the counter as you should.

注意:stateCounter < 0意味着有更多的停止活动而不是开始,这是不可能的。如果你遇到这种情况,那就意味着你没有增加/减少计数器。

You are ready to go. You should want to check if your application is on background inside onStop().

你准备好了。您应该检查您的应用程序是否处于onStop()的后台。

#5


9  

Since Android API 16 there is a simple way to check if app is in foreground. It may not be foolproof, but no methods on Android are foolproof. This method is good enough to use when your service receives update from server and has to decide whether to show notification, or not (because if UI is foreground, user will notice the update without notification).

因为Android API 16有一个简单的方法来检查app是否在前台。这可能并非万无一失,但Android上的任何方法都是万无一失的。当您的服务接收到来自服务器的更新,并且必须决定是否显示通知(因为如果UI是前台的,用户会在没有通知的情况下通知更新),这个方法就足够好了。

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;

#6


6  

There is no way, short of you tracking it yourself, to determine if any of your activities are visible or not. Perhaps you should consider asking a new * question, explaining what it is you are trying to achieve from a user experience, so we can perhaps give you alternative implementation ideas.

没有办法,你自己追踪它,以确定你的活动是否可见。也许你应该考虑问一个新的*问题,解释你想从用户体验中获得什么,所以我们也许可以给你一些备选的实现方案。

#7


5  

GOOGLE SOLUTION - not a hack, like previous solutions. Use ProcessLifecycleOwner

谷歌解决方案——不像以前的解决方案那样是一个hack。使用ProcessLifecycleOwner

class ArchLifecycleApp : Application(), LifecycleObserver {

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

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        //App in background
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onAppForegrounded() {
        // App in foreground
    }

}

in app.gradle

在app.gradle

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

allprojects {
    repositories {
        ...
        google()
        jcenter()
        maven { url 'https://maven.google.com' }
    }
}

#8


4  

You can use ComponentCallbacks2 to detect if the app is in background. BTW this callback is only available in API Level 14 (Ice Cream Sandwich) and above.

您可以使用ComponentCallbacks2来检测应用程序是否处于后台。这个回调只在API级别14(冰激凌三明治)和以上。

You will get a call to the method:

你会接到一个电话:

public abstract void onTrimMemory (int level)

公共抽象void onTrimMemory (int级)

if the level is ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN then the app is in background.

如果级别是ComponentCallbacks2。TRIM_MEMORY_UI_HIDDEN然后应用程序在后台。

You can implement this interface to an activity, service, etc.

您可以将此接口实现为活动、服务等。

public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
   @Override
   public void onConfigurationChanged(final Configuration newConfig) {

   }

   @Override
   public void onLowMemory() {

   }

   @Override
   public void onTrimMemory(final int level) {
     if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        // app is in background
     }
   }
}

#9


3  

Building on @Cornstalks answer to include a couple of useful features.

在@ corn秸秆上构建的答案包含了一些有用的特性。

Extra features:

额外的功能:

  • introduced singleton pattern so you can do this anywhere in the application: AppLifecycleHandler.isApplicationVisible() and AppLifecycleHandler.isApplicationInForeground()
  • 引入了单例模式,因此您可以在应用程序的任何地方执行此模式:AppLifecycleHandler.isApplicationVisible()和applifecyclehandler.isapplicationin前台()
  • added handling of duplicate events (see comments // take some action on change of visibility and // take some action on change of in foreground)
  • 增加对重复事件的处理(见注释//对可见性的变化采取一些行动和//对前景的变化采取一些行动)

App.java

App.java

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
    }
}

AppLifecycleHandler.java

AppLifecycleHandler.java

public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
    private int resumed;
    private int started;

    private final String DebugName = "AppLifecycleHandler";

    private boolean isVisible = false;
    private boolean isInForeground = false;

    private static AppLifecycleHandler instance;

    public static AppLifecycleHandler getInstance() {
        if (instance == null) {
            instance = new AppLifecycleHandler();
        }

        return instance;
    }

    private AppLifecycleHandler() {
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {
        ++resumed;
        android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

    @Override
    public void onActivityPaused(Activity activity) {
        --resumed;
        android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

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

    @Override
    public void onActivityStarted(Activity activity) {
        ++started;
        android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    @Override
    public void onActivityStopped(Activity activity) {
        --started;
        android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    private void setVisible(boolean visible) {
        if (isVisible == visible) {
            // no change
            return;
        }

        // visibility changed
        isVisible = visible;
        android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);

        // take some action on change of visibility
    }

    private void setForeground(boolean inForeground) {
        if (isInForeground == inForeground) {
            // no change
            return;
        }

        // in foreground changed
        isInForeground = inForeground;
        android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);

        // take some action on change of in foreground

    }

    public static boolean isApplicationVisible() {
        return AppLifecycleHandler.getInstance().started > 0;
    }

    public static boolean isApplicationInForeground() {
        return AppLifecycleHandler.getInstance().resumed > 0;
    }
}

#10


2  

To piggyback on what CommonsWare and Key have said, you could perhaps extend the Application class and have all of your activities call that on their onPause/onResume methods. This would allow you to know which Activity(ies) are visible, but this could probably be handled better.

要使用CommonsWare和Key所说的,您可以扩展应用程序类,并将所有的活动调用在onPause/onResume方法上。这将允许您知道哪些活动(ies)是可见的,但这可能会得到更好的处理。

Can you elaborate on what you have in mind exactly? When you say running in the background do you mean simply having your application still in memory even though it is not currently on screen? Have you looked into using Services as a more persistent way to manage your app when it is not in focus?

你能详细阐述一下你的想法吗?当你说在后台运行时,你的意思是你的应用程序仍然在内存中,即使它现在不在屏幕上?当你的应用不集中的时候,你有没有考虑过使用服务作为一种更持久的方式来管理你的应用?

#11


2  

I did my own implementation of ActivityLifecycleCallbacks. I'm using SherlockActivity, but for normal Activity class might work.

我自己实现了ActivityLifecycleCallbacks。我使用的是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中,您将看到在MyApplication中所做的接口实现中编程的日志。

#12


2  

The best solution I have come up with uses timers.

我提出的最好的解决方案是使用计时器。

You have start a timer in onPause() and cancel the same timer in onResume(), there is 1 instance of the Timer (usually defined in the Application class). The timer itself is set to run a Runnable after 2 seconds (or whatever interval you think is appropriate), when the timer fires you set a flag marking the application as being in the background.

您已经在onPause()中启动了一个计时器,并在onResume()中取消了相同的计时器(),其中有一个计时器实例(通常在应用程序类中定义)。计时器本身设置为在2秒后运行Runnable(或者您认为合适的时间间隔),当计时器触发时,您设置一个标记应用程序为背景的标志。

In the onResume() method before you cancel the timer, you can query the background flag to perform any startup operations (e.g. start downloads or enable location services).

在取消定时器之前,在onResume()方法中,可以查询背景标志以执行任何启动操作(例如启动下载或启用位置服务)。

This solution allows you to have several activities on the back stack, and doesn't require any permissions to implement.

这个解决方案允许您在后栈上有多个活动,并且不需要任何权限来实现。

This solution works well if you use an event bus too, as your timer can simply fire an event and various parts of your app can respond accordingly.

如果您使用的是事件总线,那么这个解决方案很有效,因为您的计时器可以简单地触发一个事件,而您的应用程序的各个部分也可以相应地做出响应。

#13


2  

If you turn on developer settings "Don't keep actvities" - check only count of created activites is not enough. You must check also isSaveInstanceState. My custom method isApplicationRunning() check is android app is running:

如果你打开开发者的设置,“不要保持空行”——只检查创建的activites的数量是不够的。您必须检查isSaveInstanceState。我的自定义方法isApplicationRunning()检查是android应用程序正在运行:

Here my work code:

在这里我的工作代码:

public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
    private int created;
    private boolean isSaveInstanceState;
    private static AppLifecycleService instance;

    private final static String TAG = AppLifecycleService.class.getName();

    public static AppLifecycleService getInstance() {
        if (instance == null) {
            instance = new AppLifecycleService();
        }
        return instance;
    }

    public static boolean isApplicationRunning() {
        boolean isApplicationRunning = true;
        if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
            isApplicationRunning = false;
        }
        return isApplicationRunning;
    }

    public static boolean isSaveInstanceState() {
        return AppLifecycleService.getInstance().isSaveInstanceState;
    }

    public static int getCountCreatedActvities() {
        return AppLifecycleService.getInstance().created;
    }

    private AppLifecycleService() {
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        this.isSaveInstanceState = true;
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
        --created;
    }

    @Override
    public void onActivityResumed(Activity activity) {   }

    @Override
    public void onActivityPaused(Activity activity) { }


    @Override
    public void onActivityStarted(Activity activity) { }

    @Override
    public void onActivityStopped(Activity activity) { }        

}

#14


1  

Activity gets paused when a Dialog comes above it so all the recommended solutions are half-solutions. You need to create hooks for dialogs as well.

当一个对话框出现在上面时,活动被暂停,因此所有推荐的解决方案都是半解决方案。您还需要为对话框创建钩子。

#15


1  

Since it isn't already mentioned, I will suggest the readers to explore ProcessLifecycleOwner available through Android Architecture components

由于还没有提到,我建议读者通过Android架构组件来探索ProcessLifecycleOwner。

#16


1  

Offical docs:

官方文档:

The system distinguishes between foreground and background apps. (The definition of background for purposes of service limitations is distinct from the definition used by memory management; an app might be in the background as pertains to memory management, but in the foreground as pertains to its ability to launch services.) An app is considered to be in the foreground if any of the following is true:

该系统区分了前景和后台应用。(服务限制目的的背景定义与内存管理的定义不同;一个应用程序可能在后台与内存管理有关,但在前景中与它启动服务的能力有关。应用程序被认为是在前景中,如果以下任何一个是正确的:

  1. It has a visible activity, whether the activity is started or paused.
  2. 它有一个可见的活动,无论活动是启动还是暂停。
  3. It has a foreground service.
  4. 它有前台服务。
  5. Another foreground app is connected to the app, either by binding to one of its services or by making use of one of its content providers. For example, the app is in the foreground if another app binds to its:
    • IME
    • 输入法设置
    • Wallpaper service
    • 壁纸服务
    • Notification listener
    • 通知侦听器
    • Voice or text service
    • 语音或文字服务
  6. 另一个前景应用程序是连接到应用程序的,要么绑定到它的某个服务,要么利用它的一个内容提供者。例如,如果另一个应用程序绑定到它的:IME墙纸服务通知侦听器语音或文本服务,该应用程序就处于前台。

If none of those conditions is true, the app is considered to be in the background.

如果这些条件都不成立,那么应用程序就被认为是在后台。

#17


0  

In my activities onResume and onPause I write an isVisible boolean to SharedPrefences.

在我的简历和onPause中,我写了一个可见的布尔值。

    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...

也许不优雅,但对我来说很有用……

#18


0  

Another solution for this old post (for those that it might help) :

这个旧邮件的另一个解决方案(对于那些可能会有帮助的人):


<application android:name=".BaseApplication" ... >

public class BaseApplication extends Application {

    private class Status {
        public boolean isVisible = true;
        public boolean isFocused = true;
    }

    private Map<Activity, Status> activities;

    @Override
    public void onCreate() {
        activities = new HashMap<Activity, Status>();
        super.onCreate();
    }

    private boolean hasVisibleActivity() {
        for (Status status : activities.values())
            if (status.isVisible)
                return true;
        return false;
    }

    private boolean hasFocusedActivity() {
        for (Status status : activities.values())
            if (status.isFocused)
                return true;
        return false;
    }

    public void onActivityCreate(Activity activity, boolean isStarting) {
        if (isStarting && activities.isEmpty())
            onApplicationStart();
        activities.put(activity, new Status());
    }

    public void onActivityStart(Activity activity) {
        if (!hasVisibleActivity() && !hasFocusedActivity())
            onApplicationForeground();
        activities.get(activity).isVisible = true;
    }

    public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
        activities.get(activity).isFocused = hasFocus;
    }

    public void onActivityStop(Activity activity, boolean isFinishing) {
        activities.get(activity).isVisible = false;
        if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
            onApplicationBackground();
    }

    public void onActivityDestroy(Activity activity, boolean isFinishing) {
        activities.remove(activity);
        if(isFinishing && activities.isEmpty())
            onApplicationStop();
    }

    private void onApplicationStart() {Log.i(null, "Start");}
    private void onApplicationBackground() {Log.i(null, "Background");}
    private void onApplicationForeground() {Log.i(null, "Foreground");}
    private void onApplicationStop() {Log.i(null, "Stop");}

}

public class MyActivity extends BaseActivity {...}

public class BaseActivity extends Activity {

    private BaseApplication application;

    @Override
    protected void onCreate(Bundle state) {
        application = (BaseApplication) getApplication();
        application.onActivityCreate(this, state == null);
        super.onCreate(state);
    }

    @Override
    protected void onStart() {
        application.onActivityStart(this);
        super.onStart();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        application.onActivityWindowFocusChanged(this, hasFocus);
        super.onWindowFocusChanged(hasFocus);
    }

    @Override
    protected void onStop() {
        application.onActivityStop(this, isFinishing());
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        application.onActivityDestroy(this, isFinishing());
        super.onDestroy();
    }

}

#19


0  

See the comment in the onActivityDestroyed function.

请参阅onActivityDestroyed函数中的注释。

Works with SDK target version 14> :

与SDK目标版本14>合作:

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;

public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {

    public static int active = 0;

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

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

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

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

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

        // if active var here ever becomes zero, the app is closed or in background
        if(active == 0){
            ...
        }

    }

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

#20


0  

You should use a shared preference to store the property and act upon it using service binding from your activities. If you use binding only, (that is never use startService), then your service would run only when you bind to it, (bind onResume and unbind onPause) that would make it run on foreground only, and if you do want to work on background you can use the regular start stop service.

您应该使用共享的首选项来存储属性,并使用您的活动中的服务绑定对其进行操作。如果你使用绑定,(即不使用startService),那么你的服务将只运行绑定到它时,(绑定onResume和unbind onPause)将使其运行在前台,如果你想研究背景可以使用常规的启动停止服务。

#21


0  

I think this question should be more clear. When? Where? What is your specific situation you want to konw if your app is in background?

我认为这个问题应该更清楚。什么时候?在哪里?如果你的应用程序在后台,你想知道的具体情况是什么?

I just introduce my solution in my way.
I get this done by using the field "importance" of RunningAppProcessInfo class in every activity's onStop method in my app, which can be simply achieved by providing a BaseActivity for other activities to extend which implements the onStop method to check the value of "importance". Here is the code:

我只是用我的方式来介绍我的解决方案。在我的应用程序中,我使用了RunningAppProcessInfo类的字段“重要性”来完成这一工作,这可以通过为其他活动提供一个BaseActivity来实现,以便扩展实现onStop方法来检查“重要性”的值。这是代码:

public static boolean isAppRunning(Context context) {
    ActivityManager activityManager = (ActivityManager) context
        .getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> appProcesses = activityManager
        .getRunningAppProcesses();
    for (RunningAppProcessInfo appProcess : appProcesses) {
        if (appProcess.processName.equals(context.getPackageName())) {
            if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
                return true;
            } 
        }
    }
    return false;
}

#22


0  

I recommend reading through this page: http://developer.android.com/reference/android/app/Activity.html

我推荐阅读这一页:http://developer.android.com/reference/android/app/Activity.html。

In short, your activity is no longer visible after onStop() has been called.

简而言之,您的活动在onStop()被调用之后不再可见。

#23


0  

What about using getApplicationState().isInForeground() ?

如何使用getApplicationState(). isin前景()?

#24


0  

In my opinion, many answers introduce a heavy load of code and bring lots of complexity and non-readability.

在我看来,许多答案都带来了大量的代码,带来了大量的复杂性和不可读性。

When people ask on SO how to communicate between a Service and a Activity, I usually advice to use the LocalBroadcastManager.

当人们询问如何在服务和活动之间进行通信时,我通常建议使用LocalBroadcastManager。


Why?

为什么?

Well, by quoting the docs:

嗯,引用文献:

  • You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.

    你知道你正在播放的数据不会离开你的应用程序,所以不要担心泄露私人数据。

  • It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.

    其他应用程序不可能将这些广播发送到您的应用程序,因此您不必担心他们可以利用安全漏洞。

  • It is more efficient than sending a global broadcast through the system.

    它比通过系统发送全球广播更有效。

Not in the the docs:

不在文档中:

  • It does not require external libraries
  • 它不需要外部库。
  • The code is minimal
  • 代码是最小的
  • It's fast to implement and understand
  • 实现和理解的速度很快。
  • No custom self-implemented callbacks / ultra-singleton / intra-process pattern whatsoever...
  • 没有自定义自实现的回调/超单实例/内部流程模式……
  • No strong references on Activity, Application, ...
  • 没有关于活动、应用、……

Description

描述

So, you want to check if any of the Activity is currently in the foreground. You usually do that in a Service, or your Application class.

因此,您需要检查当前是否有任何活动在前台。您通常在服务或应用程序类中这样做。

This means, your Activity objects become the sender of a signal (I'm on / I'm off). Your Service, on the other hand, becomes the Receiver.

这意味着,您的活动对象将成为一个信号的发送方(我正在/我不在)。另一方面,你的服务成为了接收者。

There are two moments in which your Activity tells you if it's going in the foreground or in the background (yes only two... not 6).

有两个时刻,你的活动告诉你它是在前台还是在后台(是的,只有两个……)不是6)。

When the Activity goes into the foreground, the onResume() method is triggered (also called after onCreate()).

当活动进入前台时,将触发onResume()方法(也称为onCreate())。

When the Activity goes in the back, onPause() is called.

当活动在返回时,onPause()被调用。

These are the moments in which your Activity should send the signal to your Service to describe its state.

在这些时刻,你的活动应该向你的服务发送信号来描述它的状态。

In case of multiple Activity's, remember the an Activity goes into the background first, then another one comes into the foreground.

在多个活动的情况下,记住一个活动先进入后台,然后另一个进入前台。

So the situation would be:*

所以情况是:*。

Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON

The Service / Application will simply keep listening for those signals and act accordingly.

服务/应用程序只会继续侦听这些信号并据此采取行动。


Code (TLDR)

代码(TLDR)

Your Service must implement a BroadcastReceiver in order to listen for signals.

您的服务必须实现一个广播接收器,以便侦听信号。

this.localBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // received data if Activity is on / off
    }
}

public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL") 

Register the Receiver in Service::onCreate()

在服务中注册接收方::onCreate()

@Override
protected void onCreate() {
    LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}

Un-register it in Service::onDestroy()

取消服务::onDestroy()

@Override
protected void onDestroy() {
    // I'm dead, no need to listen to anything anymore.
    LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}

Now your Activity's must communicated their state.

现在你的活动必须传达他们的状态。

In Activity::onResume()

在活动::onResume()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

In Activity::onPause()

在活动::onPause()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

A very, very common situation

这是非常非常普遍的情况。

Developer: I want to send data from my Service and update the Activity. How do I check if the Activity is in the foreground?

开发人员:我想从我的服务中发送数据并更新活动。我如何检查活动是否在前台?

There is usually no need to check if the Activity is in the foreground or not. Just send the data via LocalBroadcastManager from your Service. If the Activity is on, then it will respond and act.

通常不需要检查活动是否在前台。只需将数据通过本地广播管理器从您的服务发送出去。如果活动在进行,它就会做出反应并采取行动。

For this very common situation, the Service becomes the sender, and the Activity implements the BroadcastReceiver.

对于这种非常常见的情况,服务成为发送者,而活动实现了广播接收器。

So, create a Receiver in your Activity. Register it in onResume() and un-register it in onPause(). There is no need to use the other life-cycle methods.

所以,在你的活动中创建一个接收器。在onResume()中注册它,并在onPause()中取消注册。没有必要使用其他的生命周期方法。

Define the Receiver behavior in onReceive() (update ListView, do this, do that, ...).

在onReceive()中定义接收方行为(更新ListView,做这个,做那个,…)。

This way the Activity will listen only if it's in the foreground and nothing will happen if it's in the back or is destroyed.

这样,活动只会在前景中听,如果它在后面或被破坏,什么也不会发生。

In case of multiple Activity's, whichever Activity is on will respond (if they also implement the Receiver).

如果有多个活动,任何活动都将响应(如果它们也实现了接收者)。

If all are in the background, nobody will respond and the signal will simply get lost.

如果一切都在后台,没有人会响应,信号就会丢失。

Send the data from the Service via Intent (see code above) by specifying the signal ID.

通过指定信号ID从服务中发送数据(参见上面的代码)。


  • Except for Multi-Window Support. It may be tricky (please test it if needed)...
  • 除了多窗口的支持。这可能有点棘手(如果需要的话,请测试一下)……

#25


-1  

It might be too late to answer but if somebody comes visiting then here is the solution I suggest, The reason(s) an app wants to know it's state of being in background or coming to foreground can be many, a few are, 1. To show toasts and notifications when the user is in BG. 2.To perform some tasks for the first time user comes from BG, like a poll, redraw etc.

可能已经来不及回答了,但是如果有人来访问,我建议的解决方案是,一个应用程序想知道它的背景或前景可以是很多,一些是,1。当用户在BG时,显示祝酒词和通知。2。要执行一些任务,第一次用户来自BG,如投票,重画等。

The solution by Idolon and others takes care of the first part, but does not for the second. If there are multiple activities in your app, and the user is switching between them, then by the time you are in second activity, the visible flag will be false. So it cannot be used deterministically.

Idolon和其他人的解决方案是第一部分,但不是第二部分。如果您的应用程序中有多个活动,并且用户在它们之间进行切换,那么当您处于第二次活动时,可视标志将是错误的。所以它不能被确定地使用。

I did something what was suggested by CommonsWare, "If the Service determines that there are no activities visible, and it remains that way for some amount of time, stop the data transfer at the next logical stopping point."

我做了一些由CommonsWare建议的事情,“如果服务确定没有可见的活动,并且它在一定的时间内保持这种方式,在下一个逻辑停止点停止数据传输。”

The line in bold is important and this can be used to achieve second item. So what I do is once I get the onActivityPaused() , don not change the visible to false directly, instead have a timer of 3 seconds (that is the max that the next activity should be launched), and if there is not onActivityResumed() call in the next 3 seconds, change visible to false. Similarly in onActivityResumed() if there is a timer then I cancel it. To sum up,the visible becomes isAppInBackground.

粗体的线条很重要,这可以用来实现第二项。所以我做的就是一旦我得到onActivityPaused(),不要直接改变可见假,而不是3秒的定时器(即应该启动下一个活动的最大值),如果没有onActivityResumed()调用在接下来的3秒,可见更改为假。同样在onactivity()中,如果有一个计时器,那么我将取消它。总而言之,可见的是isAppInBackground。

Sorry cannot copy-paste the code...

抱歉不能复制代码…

#26


-1  

Another simple and accurate solution. Complete gist here

另一个简单而准确的解决方案。这里完整的要点

public class BaseLifeCycleCallbacks implements Application.ActivityLifecycleCallbacks {


HashMap<String, Integer> activities;

BaseLifeCycleCallbacks() {
    activities = new HashMap<String, Integer>();
}

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

@Override
public void onActivityStarted(Activity activity) {
    //map Activity unique class name with 1 on foreground
    activities.put(activity.getLocalClassName(), 1);
    applicationStatus();
}

@Override
public void onActivityResumed(Activity activity) {
}

@Override
public void onActivityPaused(Activity activity) {
}

@Override
public void onActivityStopped(Activity activity) {
    //map Activity unique class name with 0 on foreground
    activities.put(activity.getLocalClassName(), 0);
    applicationStatus();
}

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

}

@Override
public void onActivityDestroyed(Activity activity) {
}

/**
 * Check if any activity is in the foreground
 */
private boolean isBackGround() {
    for (String s : activities.keySet()) {
        if (activities.get(s) == 1) {
            return false;
        }
    }
    return true;
}

/**
 * Log application status.
 */
private void applicationStatus() {
    Log.d("ApplicationStatus", "Is application background" + isBackGround());
    if (isBackGround()) {
        //Do something if the application is in background
    }
}

#27


-3  

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>指定的时间范围,则意味着您的应用程序被停止,或者被系统或用户自己杀死。

#1


362  

There are few ways to detect whether your application is running in the background, but only one of them is completely reliable:

有几种方法可以检测您的应用程序是否在后台运行,但是其中只有一个是完全可靠的:

  1. The right solution (credits go to Dan, CommonsWare and NeTeInStEiN)
    Track visibility of your application by yourself using Activity.onPause, Activity.onResume methods. Store "visibility" status in some other class. Good choices are your own implementation of the Application or a Service (there are also a few variations of this solution if you'd like to check activity visibility from the service).
     
    Example
    Implement custom Application class (note the isActivityVisible() static method):

    正确的解决方案(归功于Dan, CommonsWare和NeTeInStEiN)使用活动来跟踪应用程序的可见性。onPause,活动。onResume方法。在其他类中存储“可见性”状态。好的选择是您自己的应用程序或服务的实现(如果您想从服务中查看活动可见性,也有一些不同的解决方案)。示例实现自定义应用程序类(注意isActivityVisible()静态方法):

    public class MyApplication extends Application {
    
      public static boolean isActivityVisible() {
        return activityVisible;
      }  
    
      public static void activityResumed() {
        activityVisible = true;
      }
    
      public static void activityPaused() {
        activityVisible = false;
      }
    
      private static boolean activityVisible;
    }
    

    Register your application class in AndroidManifest.xml:

    在AndroidManifest.xml中注册您的应用程序类。

    <application
        android:name="your.app.package.MyApplication"
        android:icon="@drawable/icon"
        android:label="@string/app_name" >
    

    Add onPause and onResume to every Activity in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended from MapActivity/ListActivity etc. you still need to write the following by hand):

    将onPause和onResume添加到项目中的每一个活动中(如果您愿意,您可以为您的活动创建一个共同的祖先,但是如果您的活动已经从MapActivity/ListActivity等扩展了,您仍然需要手工编写以下内容):

    @Override
    protected void onResume() {
      super.onResume();
      MyApplication.activityResumed();
    }
    
    @Override
    protected void onPause() {
      super.onPause();
      MyApplication.activityPaused();
    }
    

     
    Update
    ActivityLifecycleCallbacks were added in API level 14 (Android 4.0). You can use them to track whether an activity of your application is currently visible to the user. Check Cornstalks' answer below for the details.

    更新ActivityLifecycleCallbacks在API级别14 (Android 4.0)中添加。您可以使用它们来跟踪应用程序的活动是否对用户可见。查看玉米秸秆的答案,了解详情。

  2. The wrong one
    I used to suggest the following solution:

    我曾经提出了一个错误的建议:

    You can detect currently foreground/background application with ActivityManager.getRunningAppProcesses() which returns a list of RunningAppProcessInfo records. To determine if your application is on the foreground check RunningAppProcessInfo.importance field for equality to RunningAppProcessInfo.IMPORTANCE_FOREGROUND while RunningAppProcessInfo.processName is equal to your application package name.

    您可以使用activitymanager . getrunningappprocess()来检测当前的前台/后台应用程序,该应用程序返回RunningAppProcessInfo记录的列表。确定您的应用程序是否在前台检查RunningAppProcessInfo。重要字段,以实现对RunningAppProcessInfo的平等。IMPORTANCE_FOREGROUND RunningAppProcessInfo。processName等于您的应用程序包名。

    Also if you call ActivityManager.getRunningAppProcesses() from your application UI thread it will return importance IMPORTANCE_FOREGROUND for your task no matter whether it is actually in the foreground or not. Call it in the background thread (for example via AsyncTask) and it will return correct results.

    如果您调用activitymanager . getrunningappprocess()从您的应用程序UI线程中,它将返回您的任务的重要性,无论它是否在前台。在后台线程(例如通过AsyncTask)调用它,它将返回正确的结果。

    While this solution may work (and it indeed works most of the time) I strongly recommend to refrain from using it. And here's why. As Dianne Hackborn wrote:

    虽然这个解决方案可能起作用(而且确实在大多数情况下是有效的),但我强烈建议不要使用它。这是为什么。Dianne Hackborn写道:

    These APIs are not there for applications to base their UI flow on, but to do things like show the user the running apps, or a task manager, or such.

    这些api并不存在于应用程序以建立其UI流的基础上,而是用于向用户显示正在运行的应用程序,或任务管理器之类的东西。

    Yes there is a list kept in memory for these things. However, it is off in another process, managed by threads running separately from yours, and not something you can count on (a) seeing in time to make the correct decision or (b) have a consistent picture by the time you return. Plus the decision about what the "next" activity to go to is always done at the point where the switch is to happen, and it is not until that exact point (where the activity state is briefly locked down to do the switch) that we actually know for sure what the next thing will be.

    是的,有一个清单保存在内存中。但是,它在另一个进程中,由与您的线程分开运行的线程管理,而不是您可以指望(a)及时做出正确的决定或(b)在您返回时具有一致的图像。加上什么“下一个”活动的决定去总是在点开关在哪里发生,直到,确切点(活动状态是暂时锁定开关),实际上我们知道接下来会是什么。

    And the implementation and global behavior here is not guaranteed to remain the same in the future.

    这里的实现和全球行为在未来不保证保持不变。

    I wish I had read this before I posted an answer on the SO, but hopefully it's not too late to admit my error.

    我希望在我把答案写在上面之前,我已经读过这篇文章,但我希望现在承认我的错误还为时不晚。

  3. Another wrong solution
    Droid-Fu library mentioned in one of the answers uses ActivityManager.getRunningTasks for its isApplicationBroughtToBackground method. See Dianne's comment above and don't use that method either.

    另一个错误的解决方案Droid-Fu库在其中一个答案中使用了ActivityManager。为其isApplicationBroughtToBackground方法进行了getRunningTasks。请参见上面的Dianne的评论,也不要使用那个方法。

#2


245  

The key is using ActivityLifecycleCallbacks (note that this requires Android API level 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 (i.e. in the background).

关键是使用ActivityLifecycleCallbacks(请注意,这需要Android API级别14 (Android 4.0))。只要检查停止活动的数量是否等于开始活动的数量。如果它们是相等的,那么你的应用程序就被搁置了。如果有更多的启动活动,您的应用程序仍然可见。如果有比暂停的活动更多的恢复,您的应用程序不仅可见,而且还在前台。有三个主要的状态,你的活动可以在,然后:可见和在前景,可见,但不是在前景,和不可见,而不是在前景(即在背景中)。

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(). 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.

这种方法的真正好处是它没有异步问题getRunningTasks(),但是您也不必修改应用程序中的每一个活动来设置/取消on重启()/ on暂停()的内容。它只是包含了几行代码,在整个应用程序中都可以使用。另外,也不需要任何古怪的权限。

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; is that a problem here?

在低内存情况下不调用onStop();这是个问题吗?

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.

这里的关键是“保持你的活动进程运行…”如果这种低内存的情况达到了,那么您的进程实际上已经被杀死了(而不仅仅是您的活动)。这意味着这种方法检查backgrounded-ness仍然有效,因为)你不能检查后台处理无论如何如果你的过程是死亡,和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. 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. 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. 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. (thanks to dpimka for refreshing my memory on this and correcting me!)

默认情况下,没有。您必须在manifest文件中显式地设置configChanges=orientation|屏幕大小(您想要的其他任何东西),并处理配置更改,否则您的活动将被销毁并重新创建。如果你不设置这个,你的活动的方法将按这个顺序被调用:onCreate -> onStart -> onResume ->(现在旋转)-> onPause -> onStop -> onDestroy -> onStart -> onStart -> onResume。正如您所看到的,没有重叠(通常情况下,两个活动在两者之间切换时非常短暂,这就是这种背景探测方法的工作原理)。为了解决这个问题,您必须设置configChanges,这样您的活动就不会被破坏。幸运的是,我已经在所有的项目中设置了configChanges,因为我的整个活动都不希望在屏幕上被破坏,所以我从来没有发现这是有问题的。(多亏了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). That's why I've updated this answer to reflect that.

当我在这个答案里说“背景”时,我的意思是“你的应用不再可见了”。Android的活动在前景中是可见的(例如,如果有透明的通知覆盖)。这就是为什么我更新了这个答案来反映这一点。

It's important to know that Android has a weird limbo moment when switching activities where nothing is in the foreground. 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).

很重要的一点是,知道Android有一个奇怪的不确定的时刻,当切换活动时,没有任何东西在前台。基于这个原因,如果你检查你的应用程序是否在前台切换(在同一应用程序中),你会被告知你不在前台(即使你的应用程序仍然是活动的app,并且是可见的)。

You can check if your app is in the foreground in your Activity's onPause() method after super.onPause(). Just remember the weird limbo state I just talked about.

你可以检查你的应用程序是否在你的Activity的onPause()方法中。onPause()方法。只记得我刚才说过的那种奇怪的不稳定状态。

You can check if your app is visible (i.e. if it's not in the background) in your Activity's onStop() method after super.onStop().

您可以检查您的应用程序是否可见(如果它不在后台),在您的活动的onStop()方法之后。onStop()。

#3


16  

Idolon's answer is error prone and much more complicated althought repeatead here check android application is in foreground or not? and here Determining the current foreground application from a background task or service

Idolon的答案是容易出错的,更复杂的althought repeatead在这里检查android应用是否在前台?在这里,从后台任务或服务中确定当前的前台应用程序。

There is a much more simpler approach:

有一种更简单的方法:

On a BaseActivity that all Activities extend:

在所有活动扩展的基础活动中:

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

要理解这种方法,请检查并行活动生命周期的这个答案:活动并行生命周期。

#4


9  

I tried the recommended solution that uses Application.ActivityLifecycleCallbacks and many others, but they didn't work as expected. Thanks to Sarge, I came up with a pretty easy and straightforward solution that I am describing below.

我尝试了使用应用程序的推荐解决方案。ActivityLifecycleCallbacks和其他许多人,但他们没有像预期的那样工作。多亏了Sarge,我想出了一个非常简单明了的解决方案。

They key of the solution is the fact of understanding that if we have ActivityA and ActivityB, and we call ActivityB from ActivityA (and not call ActivityA.finish), then ActivityB's onStart() will be called before ActivityA onStop().

解决方案的关键是要了解,如果我们有ActivityA和ActivityB,我们从ActivityA(不叫ActivityA.finish)中调用ActivityB,那么ActivityB的onStart()将在ActivityA onStop()之前被调用。

That's also the main difference between onStop() and onPause() that none did mention in the articles I read.

这也是onStop()和onPause()之间的主要区别,在我阅读的文章中没有提到。

So based on this Activity's Lifecycle behavior, you can simply count how many times did onStart() and onPause() got called in your program. Note that for each Activity of your program, you must override onStart() and onStop(), in order to increment/decrement the static variable used for counting. Below is the code implementing this logic. Note that I am using a class that extends Application, so dont forget to declare on Manifest.xml inside Application tag: android:name=".Utilities", although it can be implemented using a simple custom class too.

因此,基于该活动的生命周期行为,您可以简单地计算onStart()和onPause()在您的程序中调用了多少次。注意,对于程序的每个活动,必须覆盖onStart()和onStop(),以增加/减少用于计数的静态变量。下面是实现该逻辑的代码。注意,我正在使用一个扩展应用程序的类,所以不要忘记在Manifest上声明。应用程序标签:android:name="。尽管它也可以使用简单的自定义类实现。

public class Utilities extends Application
{
    private static int stateCounter;

    public void onCreate()
    {
        super.onCreate();
        stateCounter = 0;
    }

    /**
     * @return true if application is on background
     * */
    public static boolean isApplicationOnBackground()
    {
        return stateCounter == 0;
    }

    //to be called on each Activity onStart()
    public static void activityStarted()
    {
        stateCounter++;
    }

    //to be called on each Activity onStop()
    public static void activityStopped()
    {
        stateCounter--;
    }
}

Now on each Activity of our program, we should override onStart() and onStop() and increment/decrement as shown below:

现在,在我们的程序的每个活动中,我们应该覆盖onStart()和onStop()和递增/递减,如下所示:

@Override
public void onStart()
{
    super.onStart();
    Utilities.activityStarted();
}

@Override
public void onStop()
{
    Utilities.activityStopped();
    if(Utilities.isApplicationOnBackground())
    {
        //you should want to check here if your application is on background
    }
    super.onStop();
}

With this logic, there are 2 possible cases:

有了这个逻辑,有两种可能的情况:

  1. stateCounter = 0 : The number of stopped is equal with the number of started Activities, which means that the application is running on the background.
  2. stateCounter = 0:停止的数量与启动活动的数量相等,这意味着应用程序在后台运行。
  3. stateCounter > 0 : The number of started is bigger than the number of stopped, which means that the application is running on the foreground.
  4. stateCounter > 0:开始的数量大于停止的数量,这意味着应用程序在前台运行。

Notice: stateCounter < 0 would mean that there are more stopped Activities rather than started, which is impossible. If you encounter this case, then it means that you are not increasing/decreasing the counter as you should.

注意:stateCounter < 0意味着有更多的停止活动而不是开始,这是不可能的。如果你遇到这种情况,那就意味着你没有增加/减少计数器。

You are ready to go. You should want to check if your application is on background inside onStop().

你准备好了。您应该检查您的应用程序是否处于onStop()的后台。

#5


9  

Since Android API 16 there is a simple way to check if app is in foreground. It may not be foolproof, but no methods on Android are foolproof. This method is good enough to use when your service receives update from server and has to decide whether to show notification, or not (because if UI is foreground, user will notice the update without notification).

因为Android API 16有一个简单的方法来检查app是否在前台。这可能并非万无一失,但Android上的任何方法都是万无一失的。当您的服务接收到来自服务器的更新,并且必须决定是否显示通知(因为如果UI是前台的,用户会在没有通知的情况下通知更新),这个方法就足够好了。

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;

#6


6  

There is no way, short of you tracking it yourself, to determine if any of your activities are visible or not. Perhaps you should consider asking a new * question, explaining what it is you are trying to achieve from a user experience, so we can perhaps give you alternative implementation ideas.

没有办法,你自己追踪它,以确定你的活动是否可见。也许你应该考虑问一个新的*问题,解释你想从用户体验中获得什么,所以我们也许可以给你一些备选的实现方案。

#7


5  

GOOGLE SOLUTION - not a hack, like previous solutions. Use ProcessLifecycleOwner

谷歌解决方案——不像以前的解决方案那样是一个hack。使用ProcessLifecycleOwner

class ArchLifecycleApp : Application(), LifecycleObserver {

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

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        //App in background
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onAppForegrounded() {
        // App in foreground
    }

}

in app.gradle

在app.gradle

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

allprojects {
    repositories {
        ...
        google()
        jcenter()
        maven { url 'https://maven.google.com' }
    }
}

#8


4  

You can use ComponentCallbacks2 to detect if the app is in background. BTW this callback is only available in API Level 14 (Ice Cream Sandwich) and above.

您可以使用ComponentCallbacks2来检测应用程序是否处于后台。这个回调只在API级别14(冰激凌三明治)和以上。

You will get a call to the method:

你会接到一个电话:

public abstract void onTrimMemory (int level)

公共抽象void onTrimMemory (int级)

if the level is ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN then the app is in background.

如果级别是ComponentCallbacks2。TRIM_MEMORY_UI_HIDDEN然后应用程序在后台。

You can implement this interface to an activity, service, etc.

您可以将此接口实现为活动、服务等。

public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
   @Override
   public void onConfigurationChanged(final Configuration newConfig) {

   }

   @Override
   public void onLowMemory() {

   }

   @Override
   public void onTrimMemory(final int level) {
     if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        // app is in background
     }
   }
}

#9


3  

Building on @Cornstalks answer to include a couple of useful features.

在@ corn秸秆上构建的答案包含了一些有用的特性。

Extra features:

额外的功能:

  • introduced singleton pattern so you can do this anywhere in the application: AppLifecycleHandler.isApplicationVisible() and AppLifecycleHandler.isApplicationInForeground()
  • 引入了单例模式,因此您可以在应用程序的任何地方执行此模式:AppLifecycleHandler.isApplicationVisible()和applifecyclehandler.isapplicationin前台()
  • added handling of duplicate events (see comments // take some action on change of visibility and // take some action on change of in foreground)
  • 增加对重复事件的处理(见注释//对可见性的变化采取一些行动和//对前景的变化采取一些行动)

App.java

App.java

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
    }
}

AppLifecycleHandler.java

AppLifecycleHandler.java

public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
    private int resumed;
    private int started;

    private final String DebugName = "AppLifecycleHandler";

    private boolean isVisible = false;
    private boolean isInForeground = false;

    private static AppLifecycleHandler instance;

    public static AppLifecycleHandler getInstance() {
        if (instance == null) {
            instance = new AppLifecycleHandler();
        }

        return instance;
    }

    private AppLifecycleHandler() {
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {
        ++resumed;
        android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

    @Override
    public void onActivityPaused(Activity activity) {
        --resumed;
        android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

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

    @Override
    public void onActivityStarted(Activity activity) {
        ++started;
        android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    @Override
    public void onActivityStopped(Activity activity) {
        --started;
        android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    private void setVisible(boolean visible) {
        if (isVisible == visible) {
            // no change
            return;
        }

        // visibility changed
        isVisible = visible;
        android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);

        // take some action on change of visibility
    }

    private void setForeground(boolean inForeground) {
        if (isInForeground == inForeground) {
            // no change
            return;
        }

        // in foreground changed
        isInForeground = inForeground;
        android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);

        // take some action on change of in foreground

    }

    public static boolean isApplicationVisible() {
        return AppLifecycleHandler.getInstance().started > 0;
    }

    public static boolean isApplicationInForeground() {
        return AppLifecycleHandler.getInstance().resumed > 0;
    }
}

#10


2  

To piggyback on what CommonsWare and Key have said, you could perhaps extend the Application class and have all of your activities call that on their onPause/onResume methods. This would allow you to know which Activity(ies) are visible, but this could probably be handled better.

要使用CommonsWare和Key所说的,您可以扩展应用程序类,并将所有的活动调用在onPause/onResume方法上。这将允许您知道哪些活动(ies)是可见的,但这可能会得到更好的处理。

Can you elaborate on what you have in mind exactly? When you say running in the background do you mean simply having your application still in memory even though it is not currently on screen? Have you looked into using Services as a more persistent way to manage your app when it is not in focus?

你能详细阐述一下你的想法吗?当你说在后台运行时,你的意思是你的应用程序仍然在内存中,即使它现在不在屏幕上?当你的应用不集中的时候,你有没有考虑过使用服务作为一种更持久的方式来管理你的应用?

#11


2  

I did my own implementation of ActivityLifecycleCallbacks. I'm using SherlockActivity, but for normal Activity class might work.

我自己实现了ActivityLifecycleCallbacks。我使用的是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中,您将看到在MyApplication中所做的接口实现中编程的日志。

#12


2  

The best solution I have come up with uses timers.

我提出的最好的解决方案是使用计时器。

You have start a timer in onPause() and cancel the same timer in onResume(), there is 1 instance of the Timer (usually defined in the Application class). The timer itself is set to run a Runnable after 2 seconds (or whatever interval you think is appropriate), when the timer fires you set a flag marking the application as being in the background.

您已经在onPause()中启动了一个计时器,并在onResume()中取消了相同的计时器(),其中有一个计时器实例(通常在应用程序类中定义)。计时器本身设置为在2秒后运行Runnable(或者您认为合适的时间间隔),当计时器触发时,您设置一个标记应用程序为背景的标志。

In the onResume() method before you cancel the timer, you can query the background flag to perform any startup operations (e.g. start downloads or enable location services).

在取消定时器之前,在onResume()方法中,可以查询背景标志以执行任何启动操作(例如启动下载或启用位置服务)。

This solution allows you to have several activities on the back stack, and doesn't require any permissions to implement.

这个解决方案允许您在后栈上有多个活动,并且不需要任何权限来实现。

This solution works well if you use an event bus too, as your timer can simply fire an event and various parts of your app can respond accordingly.

如果您使用的是事件总线,那么这个解决方案很有效,因为您的计时器可以简单地触发一个事件,而您的应用程序的各个部分也可以相应地做出响应。

#13


2  

If you turn on developer settings "Don't keep actvities" - check only count of created activites is not enough. You must check also isSaveInstanceState. My custom method isApplicationRunning() check is android app is running:

如果你打开开发者的设置,“不要保持空行”——只检查创建的activites的数量是不够的。您必须检查isSaveInstanceState。我的自定义方法isApplicationRunning()检查是android应用程序正在运行:

Here my work code:

在这里我的工作代码:

public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
    private int created;
    private boolean isSaveInstanceState;
    private static AppLifecycleService instance;

    private final static String TAG = AppLifecycleService.class.getName();

    public static AppLifecycleService getInstance() {
        if (instance == null) {
            instance = new AppLifecycleService();
        }
        return instance;
    }

    public static boolean isApplicationRunning() {
        boolean isApplicationRunning = true;
        if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
            isApplicationRunning = false;
        }
        return isApplicationRunning;
    }

    public static boolean isSaveInstanceState() {
        return AppLifecycleService.getInstance().isSaveInstanceState;
    }

    public static int getCountCreatedActvities() {
        return AppLifecycleService.getInstance().created;
    }

    private AppLifecycleService() {
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        this.isSaveInstanceState = true;
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
        --created;
    }

    @Override
    public void onActivityResumed(Activity activity) {   }

    @Override
    public void onActivityPaused(Activity activity) { }


    @Override
    public void onActivityStarted(Activity activity) { }

    @Override
    public void onActivityStopped(Activity activity) { }        

}

#14


1  

Activity gets paused when a Dialog comes above it so all the recommended solutions are half-solutions. You need to create hooks for dialogs as well.

当一个对话框出现在上面时,活动被暂停,因此所有推荐的解决方案都是半解决方案。您还需要为对话框创建钩子。

#15


1  

Since it isn't already mentioned, I will suggest the readers to explore ProcessLifecycleOwner available through Android Architecture components

由于还没有提到,我建议读者通过Android架构组件来探索ProcessLifecycleOwner。

#16


1  

Offical docs:

官方文档:

The system distinguishes between foreground and background apps. (The definition of background for purposes of service limitations is distinct from the definition used by memory management; an app might be in the background as pertains to memory management, but in the foreground as pertains to its ability to launch services.) An app is considered to be in the foreground if any of the following is true:

该系统区分了前景和后台应用。(服务限制目的的背景定义与内存管理的定义不同;一个应用程序可能在后台与内存管理有关,但在前景中与它启动服务的能力有关。应用程序被认为是在前景中,如果以下任何一个是正确的:

  1. It has a visible activity, whether the activity is started or paused.
  2. 它有一个可见的活动,无论活动是启动还是暂停。
  3. It has a foreground service.
  4. 它有前台服务。
  5. Another foreground app is connected to the app, either by binding to one of its services or by making use of one of its content providers. For example, the app is in the foreground if another app binds to its:
    • IME
    • 输入法设置
    • Wallpaper service
    • 壁纸服务
    • Notification listener
    • 通知侦听器
    • Voice or text service
    • 语音或文字服务
  6. 另一个前景应用程序是连接到应用程序的,要么绑定到它的某个服务,要么利用它的一个内容提供者。例如,如果另一个应用程序绑定到它的:IME墙纸服务通知侦听器语音或文本服务,该应用程序就处于前台。

If none of those conditions is true, the app is considered to be in the background.

如果这些条件都不成立,那么应用程序就被认为是在后台。

#17


0  

In my activities onResume and onPause I write an isVisible boolean to SharedPrefences.

在我的简历和onPause中,我写了一个可见的布尔值。

    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...

也许不优雅,但对我来说很有用……

#18


0  

Another solution for this old post (for those that it might help) :

这个旧邮件的另一个解决方案(对于那些可能会有帮助的人):


<application android:name=".BaseApplication" ... >

public class BaseApplication extends Application {

    private class Status {
        public boolean isVisible = true;
        public boolean isFocused = true;
    }

    private Map<Activity, Status> activities;

    @Override
    public void onCreate() {
        activities = new HashMap<Activity, Status>();
        super.onCreate();
    }

    private boolean hasVisibleActivity() {
        for (Status status : activities.values())
            if (status.isVisible)
                return true;
        return false;
    }

    private boolean hasFocusedActivity() {
        for (Status status : activities.values())
            if (status.isFocused)
                return true;
        return false;
    }

    public void onActivityCreate(Activity activity, boolean isStarting) {
        if (isStarting && activities.isEmpty())
            onApplicationStart();
        activities.put(activity, new Status());
    }

    public void onActivityStart(Activity activity) {
        if (!hasVisibleActivity() && !hasFocusedActivity())
            onApplicationForeground();
        activities.get(activity).isVisible = true;
    }

    public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
        activities.get(activity).isFocused = hasFocus;
    }

    public void onActivityStop(Activity activity, boolean isFinishing) {
        activities.get(activity).isVisible = false;
        if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
            onApplicationBackground();
    }

    public void onActivityDestroy(Activity activity, boolean isFinishing) {
        activities.remove(activity);
        if(isFinishing && activities.isEmpty())
            onApplicationStop();
    }

    private void onApplicationStart() {Log.i(null, "Start");}
    private void onApplicationBackground() {Log.i(null, "Background");}
    private void onApplicationForeground() {Log.i(null, "Foreground");}
    private void onApplicationStop() {Log.i(null, "Stop");}

}

public class MyActivity extends BaseActivity {...}

public class BaseActivity extends Activity {

    private BaseApplication application;

    @Override
    protected void onCreate(Bundle state) {
        application = (BaseApplication) getApplication();
        application.onActivityCreate(this, state == null);
        super.onCreate(state);
    }

    @Override
    protected void onStart() {
        application.onActivityStart(this);
        super.onStart();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        application.onActivityWindowFocusChanged(this, hasFocus);
        super.onWindowFocusChanged(hasFocus);
    }

    @Override
    protected void onStop() {
        application.onActivityStop(this, isFinishing());
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        application.onActivityDestroy(this, isFinishing());
        super.onDestroy();
    }

}

#19


0  

See the comment in the onActivityDestroyed function.

请参阅onActivityDestroyed函数中的注释。

Works with SDK target version 14> :

与SDK目标版本14>合作:

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;

public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {

    public static int active = 0;

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

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

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

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

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

        // if active var here ever becomes zero, the app is closed or in background
        if(active == 0){
            ...
        }

    }

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

#20


0  

You should use a shared preference to store the property and act upon it using service binding from your activities. If you use binding only, (that is never use startService), then your service would run only when you bind to it, (bind onResume and unbind onPause) that would make it run on foreground only, and if you do want to work on background you can use the regular start stop service.

您应该使用共享的首选项来存储属性,并使用您的活动中的服务绑定对其进行操作。如果你使用绑定,(即不使用startService),那么你的服务将只运行绑定到它时,(绑定onResume和unbind onPause)将使其运行在前台,如果你想研究背景可以使用常规的启动停止服务。

#21


0  

I think this question should be more clear. When? Where? What is your specific situation you want to konw if your app is in background?

我认为这个问题应该更清楚。什么时候?在哪里?如果你的应用程序在后台,你想知道的具体情况是什么?

I just introduce my solution in my way.
I get this done by using the field "importance" of RunningAppProcessInfo class in every activity's onStop method in my app, which can be simply achieved by providing a BaseActivity for other activities to extend which implements the onStop method to check the value of "importance". Here is the code:

我只是用我的方式来介绍我的解决方案。在我的应用程序中,我使用了RunningAppProcessInfo类的字段“重要性”来完成这一工作,这可以通过为其他活动提供一个BaseActivity来实现,以便扩展实现onStop方法来检查“重要性”的值。这是代码:

public static boolean isAppRunning(Context context) {
    ActivityManager activityManager = (ActivityManager) context
        .getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> appProcesses = activityManager
        .getRunningAppProcesses();
    for (RunningAppProcessInfo appProcess : appProcesses) {
        if (appProcess.processName.equals(context.getPackageName())) {
            if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
                return true;
            } 
        }
    }
    return false;
}

#22


0  

I recommend reading through this page: http://developer.android.com/reference/android/app/Activity.html

我推荐阅读这一页:http://developer.android.com/reference/android/app/Activity.html。

In short, your activity is no longer visible after onStop() has been called.

简而言之,您的活动在onStop()被调用之后不再可见。

#23


0  

What about using getApplicationState().isInForeground() ?

如何使用getApplicationState(). isin前景()?

#24


0  

In my opinion, many answers introduce a heavy load of code and bring lots of complexity and non-readability.

在我看来,许多答案都带来了大量的代码,带来了大量的复杂性和不可读性。

When people ask on SO how to communicate between a Service and a Activity, I usually advice to use the LocalBroadcastManager.

当人们询问如何在服务和活动之间进行通信时,我通常建议使用LocalBroadcastManager。


Why?

为什么?

Well, by quoting the docs:

嗯,引用文献:

  • You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.

    你知道你正在播放的数据不会离开你的应用程序,所以不要担心泄露私人数据。

  • It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.

    其他应用程序不可能将这些广播发送到您的应用程序,因此您不必担心他们可以利用安全漏洞。

  • It is more efficient than sending a global broadcast through the system.

    它比通过系统发送全球广播更有效。

Not in the the docs:

不在文档中:

  • It does not require external libraries
  • 它不需要外部库。
  • The code is minimal
  • 代码是最小的
  • It's fast to implement and understand
  • 实现和理解的速度很快。
  • No custom self-implemented callbacks / ultra-singleton / intra-process pattern whatsoever...
  • 没有自定义自实现的回调/超单实例/内部流程模式……
  • No strong references on Activity, Application, ...
  • 没有关于活动、应用、……

Description

描述

So, you want to check if any of the Activity is currently in the foreground. You usually do that in a Service, or your Application class.

因此,您需要检查当前是否有任何活动在前台。您通常在服务或应用程序类中这样做。

This means, your Activity objects become the sender of a signal (I'm on / I'm off). Your Service, on the other hand, becomes the Receiver.

这意味着,您的活动对象将成为一个信号的发送方(我正在/我不在)。另一方面,你的服务成为了接收者。

There are two moments in which your Activity tells you if it's going in the foreground or in the background (yes only two... not 6).

有两个时刻,你的活动告诉你它是在前台还是在后台(是的,只有两个……)不是6)。

When the Activity goes into the foreground, the onResume() method is triggered (also called after onCreate()).

当活动进入前台时,将触发onResume()方法(也称为onCreate())。

When the Activity goes in the back, onPause() is called.

当活动在返回时,onPause()被调用。

These are the moments in which your Activity should send the signal to your Service to describe its state.

在这些时刻,你的活动应该向你的服务发送信号来描述它的状态。

In case of multiple Activity's, remember the an Activity goes into the background first, then another one comes into the foreground.

在多个活动的情况下,记住一个活动先进入后台,然后另一个进入前台。

So the situation would be:*

所以情况是:*。

Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON

The Service / Application will simply keep listening for those signals and act accordingly.

服务/应用程序只会继续侦听这些信号并据此采取行动。


Code (TLDR)

代码(TLDR)

Your Service must implement a BroadcastReceiver in order to listen for signals.

您的服务必须实现一个广播接收器,以便侦听信号。

this.localBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // received data if Activity is on / off
    }
}

public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL") 

Register the Receiver in Service::onCreate()

在服务中注册接收方::onCreate()

@Override
protected void onCreate() {
    LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}

Un-register it in Service::onDestroy()

取消服务::onDestroy()

@Override
protected void onDestroy() {
    // I'm dead, no need to listen to anything anymore.
    LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}

Now your Activity's must communicated their state.

现在你的活动必须传达他们的状态。

In Activity::onResume()

在活动::onResume()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

In Activity::onPause()

在活动::onPause()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

A very, very common situation

这是非常非常普遍的情况。

Developer: I want to send data from my Service and update the Activity. How do I check if the Activity is in the foreground?

开发人员:我想从我的服务中发送数据并更新活动。我如何检查活动是否在前台?

There is usually no need to check if the Activity is in the foreground or not. Just send the data via LocalBroadcastManager from your Service. If the Activity is on, then it will respond and act.

通常不需要检查活动是否在前台。只需将数据通过本地广播管理器从您的服务发送出去。如果活动在进行,它就会做出反应并采取行动。

For this very common situation, the Service becomes the sender, and the Activity implements the BroadcastReceiver.

对于这种非常常见的情况,服务成为发送者,而活动实现了广播接收器。

So, create a Receiver in your Activity. Register it in onResume() and un-register it in onPause(). There is no need to use the other life-cycle methods.

所以,在你的活动中创建一个接收器。在onResume()中注册它,并在onPause()中取消注册。没有必要使用其他的生命周期方法。

Define the Receiver behavior in onReceive() (update ListView, do this, do that, ...).

在onReceive()中定义接收方行为(更新ListView,做这个,做那个,…)。

This way the Activity will listen only if it's in the foreground and nothing will happen if it's in the back or is destroyed.

这样,活动只会在前景中听,如果它在后面或被破坏,什么也不会发生。

In case of multiple Activity's, whichever Activity is on will respond (if they also implement the Receiver).

如果有多个活动,任何活动都将响应(如果它们也实现了接收者)。

If all are in the background, nobody will respond and the signal will simply get lost.

如果一切都在后台,没有人会响应,信号就会丢失。

Send the data from the Service via Intent (see code above) by specifying the signal ID.

通过指定信号ID从服务中发送数据(参见上面的代码)。


  • Except for Multi-Window Support. It may be tricky (please test it if needed)...
  • 除了多窗口的支持。这可能有点棘手(如果需要的话,请测试一下)……

#25


-1  

It might be too late to answer but if somebody comes visiting then here is the solution I suggest, The reason(s) an app wants to know it's state of being in background or coming to foreground can be many, a few are, 1. To show toasts and notifications when the user is in BG. 2.To perform some tasks for the first time user comes from BG, like a poll, redraw etc.

可能已经来不及回答了,但是如果有人来访问,我建议的解决方案是,一个应用程序想知道它的背景或前景可以是很多,一些是,1。当用户在BG时,显示祝酒词和通知。2。要执行一些任务,第一次用户来自BG,如投票,重画等。

The solution by Idolon and others takes care of the first part, but does not for the second. If there are multiple activities in your app, and the user is switching between them, then by the time you are in second activity, the visible flag will be false. So it cannot be used deterministically.

Idolon和其他人的解决方案是第一部分,但不是第二部分。如果您的应用程序中有多个活动,并且用户在它们之间进行切换,那么当您处于第二次活动时,可视标志将是错误的。所以它不能被确定地使用。

I did something what was suggested by CommonsWare, "If the Service determines that there are no activities visible, and it remains that way for some amount of time, stop the data transfer at the next logical stopping point."

我做了一些由CommonsWare建议的事情,“如果服务确定没有可见的活动,并且它在一定的时间内保持这种方式,在下一个逻辑停止点停止数据传输。”

The line in bold is important and this can be used to achieve second item. So what I do is once I get the onActivityPaused() , don not change the visible to false directly, instead have a timer of 3 seconds (that is the max that the next activity should be launched), and if there is not onActivityResumed() call in the next 3 seconds, change visible to false. Similarly in onActivityResumed() if there is a timer then I cancel it. To sum up,the visible becomes isAppInBackground.

粗体的线条很重要,这可以用来实现第二项。所以我做的就是一旦我得到onActivityPaused(),不要直接改变可见假,而不是3秒的定时器(即应该启动下一个活动的最大值),如果没有onActivityResumed()调用在接下来的3秒,可见更改为假。同样在onactivity()中,如果有一个计时器,那么我将取消它。总而言之,可见的是isAppInBackground。

Sorry cannot copy-paste the code...

抱歉不能复制代码…

#26


-1  

Another simple and accurate solution. Complete gist here

另一个简单而准确的解决方案。这里完整的要点

public class BaseLifeCycleCallbacks implements Application.ActivityLifecycleCallbacks {


HashMap<String, Integer> activities;

BaseLifeCycleCallbacks() {
    activities = new HashMap<String, Integer>();
}

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

@Override
public void onActivityStarted(Activity activity) {
    //map Activity unique class name with 1 on foreground
    activities.put(activity.getLocalClassName(), 1);
    applicationStatus();
}

@Override
public void onActivityResumed(Activity activity) {
}

@Override
public void onActivityPaused(Activity activity) {
}

@Override
public void onActivityStopped(Activity activity) {
    //map Activity unique class name with 0 on foreground
    activities.put(activity.getLocalClassName(), 0);
    applicationStatus();
}

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

}

@Override
public void onActivityDestroyed(Activity activity) {
}

/**
 * Check if any activity is in the foreground
 */
private boolean isBackGround() {
    for (String s : activities.keySet()) {
        if (activities.get(s) == 1) {
            return false;
        }
    }
    return true;
}

/**
 * Log application status.
 */
private void applicationStatus() {
    Log.d("ApplicationStatus", "Is application background" + isBackGround());
    if (isBackGround()) {
        //Do something if the application is in background
    }
}

#27


-3  

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>指定的时间范围,则意味着您的应用程序被停止,或者被系统或用户自己杀死。