检查 Android 应用程序是否在后台运行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3667022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Checking if an Android application is running in the background
提问by cppdev
By background, I mean none of the application's activities are currently visible to the user?
通过背景,我的意思是用户当前看不到应用程序的所有活动?
回答by Idolon
There are few ways to detect whether your application is running in the background, but only one of them is completely reliable:
有几种方法可以检测您的应用程序是否在后台运行,但只有其中一种是完全可靠的:
The right solution(credits go to Dan, CommonsWareand NeTeInStEiN)
Track visibility of your application by yourself usingActivity.onPause
,Activity.onResume
methods. Store "visibility" status in some other class. Good choices are your own implementation of theApplication
or aService
(there are also a few variationsof this solution if you'd like to check activity visibility from the service).
Example
Implement customApplication
class (note theisActivityVisible()
static method):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
:<application android:name="your.app.package.MyApplication" android:icon="@drawable/icon" android:label="@string/app_name" >
Add
onPause
andonResume
to everyActivity
in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended fromMapActivity
/ListActivity
etc. you still need to write the following by hand):@Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); }
Update
ActivityLifecycleCallbackswere 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' answerbelow for the details.The wrong one
I used to suggest the following solution:You can detect currently foreground/background application with
ActivityManager.getRunningAppProcesses()
which returns a list ofRunningAppProcessInfo
records. To determine if your application is on the foreground checkRunningAppProcessInfo.importance
field for equality toRunningAppProcessInfo.IMPORTANCE_FOREGROUND
whileRunningAppProcessInfo.processName
is equal to your application package name.Also if you call
ActivityManager.getRunningAppProcesses()
from your application UI thread it will return importanceIMPORTANCE_FOREGROUND
for your task no matter whether it is actually in the foreground or not. Call it in the background thread (for example viaAsyncTask
) and it will return correct results.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:
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.
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.
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.
Another wrong solution
Droid-Fulibrary mentioned in one of the answers usesActivityManager.getRunningTasks
for itsisApplicationBroughtToBackground
method. See Dianne's comment above and don't use that method either.
正确的解决方案(归功于Dan、CommonsWare和NeTeInStEiN)
使用Activity.onPause
,Activity.onResume
方法自行跟踪应用程序的可见性。在其他一些类中存储“可见性”状态。好的选择是您自己实现Application
或 aService
(如果您想检查服务的活动可见性,此解决方案也有一些变体)。
示例
实现自定义Application
类(注意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; }
在以下位置注册您的应用程序类
AndroidManifest.xml
:<application android:name="your.app.package.MyApplication" android:icon="@drawable/icon" android:label="@string/app_name" >
添加
onPause
和添加onResume
到每个Activity
项目中(如果您愿意,您可以为您的活动创建一个共同的祖先,但如果您的活动已经从MapActivity
/ListActivity
等扩展,您仍然需要手动编写以下内容):@Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); }
在 API 级别 14 (Android 4.0) 中添加了更新
ActivityLifecycleCallbacks。您可以使用它们来跟踪您的应用程序的活动当前是否对用户可见。有关详细信息,请查看下面的Cornstalks 的回答。
我曾经错误地建议以下解决方案:您可以检测当前
ActivityManager.getRunningAppProcesses()
返回RunningAppProcessInfo
记录列表的前台/后台应用程序。确定您的应用程序是否在前台检查RunningAppProcessInfo.importance
字段是否等于RunningAppProcessInfo.IMPORTANCE_FOREGROUND
whileRunningAppProcessInfo.processName
等于您的应用程序包名称。此外,如果您
ActivityManager.getRunningAppProcesses()
从应用程序 UI 线程调用,IMPORTANCE_FOREGROUND
无论它实际上是否在前台,它都会为您的任务返回重要性。在后台线程中调用它(例如通过AsyncTask
),它将返回正确的结果。尽管此解决方案可能有效(并且在大多数情况下确实有效),但我强烈建议您不要使用它。这就是原因。正如黛安·哈克伯恩 (Dianne Hackborn) 所写:
这些 API 不是让应用程序基于其 UI 流程,而是用来执行诸如向用户显示正在运行的应用程序或任务管理器之类的事情。
是的,有一个列表保存在这些东西的内存中。但是,它在另一个进程中关闭,由与您的线程分开运行的线程管理,而不是您可以指望 (a) 及时看到以做出正确决定或 (b) 在您返回时拥有一致的图片。另外,关于“下一个”活动要进行什么的决定总是在切换发生的时候完成,直到那个确切的点(活动状态被短暂锁定以进行切换)我们才实际上知道接下来会发生什么。
并且不能保证这里的实现和全局行为在未来保持不变。
我希望在我在 SO 上发布答案之前读过这篇文章,但希望现在承认我的错误还为时不晚。
在其中一个答案中提到的另一个错误的解决方案
Droid-Fu库ActivityManager.getRunningTasks
用于其isApplicationBroughtToBackground
方法。请参阅上面 Dianne 的评论,也不要使用该方法。
回答by Cornstalks
DO NOT USE THIS ANSWER
不要使用这个答案
user1269737's answer is the proper (Google/Android approved) way to do this. Go read their answer and give them a +1.
user1269737 的回答是正确的(Google/Android 批准的)方法来做到这一点。去阅读他们的答案并给他们 +1。
I'll leave my original answer here for posterity's sake. This was the best available back in 2012, but now Android has proper support for this.
为了后代,我将把我原来的答案留在这里。这是 2012 年最好的,但现在 Android 对此有适当的支持。
Original answer
原答案
The key is using ActivityLifecycleCallbacks
(note that this requires Android API level 14 (Android 4.0)). 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))。只需检查已停止活动的数量是否等于已启动的活动数量。如果它们相等,则您的应用程序正在后台运行。如果有更多已启动的活动,您的应用程序仍然可见。如果恢复的活动多于暂停的活动,则您的应用程序不仅可见,而且还在前台。您的 Activity 可以处于 3 种主要状态,然后:可见且在前台,可见但不在前台,不可见且不在前台(即在后台)。
The really nice thing about this method is that it doesn't have the asynchronous issues getRunningTasks()
does, but you also don't have to modify every Activity
in your application to set/unset something in onResumed()
/onPaused()
. 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()
,但你也不必修改每一个Activity
在你的应用程序中设置/取消的东西onResumed()
/ onPaused()
。它只是自包含的几行代码,它适用于您的整个应用程序。另外,也不需要时髦的权限。
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:
我的应用程序.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
.
这里的关键是“保持您的活动进程运行......”如果达到这种低内存情况,您的进程实际上会被杀死(不仅仅是您的活动)。这意味着这种检查后台的方法仍然有效,因为 a) 如果您的进程被终止,无论如何您都无法检查后台,并且 b) 如果您的进程再次启动(因为创建了一个新活动),成员变量(无论是否静态)MyLifecycleHandler
将重置为0
.
Does this work for configuration changes?
这适用于配置更改吗?
By default, no. You have to explicitly set configChanges=orientation|screensize
(|
with anything else you want) in your manifest file and handle the configuration changes, or else your activity will be destroyed and recreated. 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!)
默认情况下,没有。您必须在清单文件中明确设置configChanges=orientation|screensize
(|
使用您想要的任何其他内容)并处理配置更改,否则您的活动将被销毁并重新创建。如果您不设置此项,您的活动的方法将按以下顺序调用:onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> 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 Activity 可以可见但不在前台(例如,如果有透明的通知覆盖)。这就是为什么我更新了这个答案以反映这一点。
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 有一个奇怪的不确定时刻。出于这个原因,如果您在 Activity 之间切换时检查您的应用程序是否在前台(在同一个应用程序中),您将被告知您不在前台(即使您的应用程序仍然是活动应用程序并且可见) )。
You can check if your app is in the foreground in your Activity
's onPause()
method aftersuper.onPause()
. Just remember the weird limbo state I just talked about.
您可以在之后Activity
的onPause()
方法中检查您的应用程序是否在前台。只要记住我刚刚谈到的奇怪的边缘状态。super.onPause()
You can check if your app is visible (i.e. if it's not in the background) in your Activity
's onStop()
method aftersuper.onStop()
.
您可以检查您的应用程序是可见的(即,如果它不是在后台)在你Activity
的onStop()
方法之后super.onStop()
。
回答by user1269737
GOOGLE SOLUTION- not a hack, like previous solutions. Use ProcessLifecycleOwner
Kotlin:
GOOGLE 解决方案- 不像以前的解决方案那样是黑客攻击。使用ProcessLifecycleOwner
Kotlin:
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
}
}
Java:
爪哇:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
}
}
in app.gradle
在 app.gradle 中
dependencies {
...
implementation "android.arch.lifecycle:extensions:1.1.0"
//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
}
allprojects {
repositories {
...
google()
jcenter()
maven { url 'https://maven.google.com' }
}
}
You can read more about Lifecycle related architecture components here - https://developer.android.com/topic/libraries/architecture/lifecycle
您可以在此处阅读有关 Lifecycle 相关架构组件的更多信息 - https://developer.android.com/topic/libraries/architecture/lifecycle
回答by Keivan Esbati
Starting support library version 26 you can use ProcessLifecycleOwner, just add it to your dependency like described here, for example:
启动支持库版本26,您可以使用ProcessLifecycleOwner,只需将其添加到您的依赖等记载这里,例如:
dependencies {
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
}
And then just query ProcessLifecycleOwner
whenever you want for app state, examples:
然后ProcessLifecycleOwner
只要你想查询应用程序状态,例子:
//Check if app is in background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;
//Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
回答by Juozas Kontvainis
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 开始,有一种简单的方法可以检查应用程序是否在前台。它可能不是万无一失的,但在 Android 上没有任何方法是万无一失的。当您的服务从服务器接收更新并且必须决定是否显示通知时(因为如果 UI 处于前台,用户将在没有通知的情况下注意到更新)时,可以使用此方法。
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
回答by neteinstein
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 的答案很容易出错,而且要复杂得多,尽管在这里重复检查 android 应用程序是否在前台?在这里从后台任务或服务中确定当前的前台应用程序
There is a much more simpler approach:
有一个更简单的方法:
On a BaseActivity that all Activities extend:
在所有活动都扩展的BaseActivity 上:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
Whenever you need to check if any of your application activities is in foreground just checkisVisible()
;
每当您需要检查您的任何应用程序活动是否在前台时,只需检查isVisible()
;
To understand this approach check this answer of side-by-side activity lifecycle: Activity side-by-side lifecycle
要了解这种方法,请查看并排活动生命周期的答案:活动并排生命周期
回答by Menelaos Kotsollaris
I tried the recommended solution that uses Application.ActivityLifecycleCallbacksand 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.
我尝试了使用Application.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'sonStart()
will be called beforeActivityAonStop()
.
他们解决方案的关键是理解如果我们有 ActivityA 和 ActivityB,并且我们从 ActivityA 调用 ActivityB(而不是 call
ActivityA.finish
),那么 ActivityBonStart()
将在ActivityA之前被调用onStop()
。
That's also the maindifference 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 eachActivity
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.
因此,基于此 Activity 的生命周期行为,您可以简单地计算程序中调用onStart()
和onPause()
调用的次数。请注意,对于Activity
您的每个程序,您必须覆盖onStart()
and onStop()
,以便增加/减少用于计数的静态变量。下面是实现这个逻辑的代码。请注意,我使用的是 extends 类Application
,所以不要忘记Manifest.xml
在 Application 标签内声明:android:name=".Utilities"
,尽管它也可以使用简单的自定义类来实现。
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:
现在在我们程序的每个 Activity 上,我们应该覆盖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:
按照这个逻辑,有两种可能的情况:
stateCounter = 0
: The number of stopped is equal with the number of started Activities, which means that the application is running on the background.stateCounter > 0
: The number of started is bigger than the number of stopped, which means that the application is running on the foreground.
stateCounter = 0
:停止的数量与启动的活动数量相等,这意味着应用程序在后台运行。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()
.
回答by CommonsWare
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 StackOverflow question, explaining what it is you are trying to achieve from a user experience, so we can perhaps give you alternative implementation ideas.
除非您自己跟踪,否则无法确定您的任何活动是否可见。也许你应该考虑提出一个新的 StackOverflow 问题,解释你试图从用户体验中实现什么,所以我们也许可以给你替代的实现想法。
回答by Rohit Arya
You can use ComponentCallbacks2to detect if the app is in background. BTW this callback is only availablein 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)
public abstract void onTrimMemory (int level)
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.
您可以实现此接口的activity
,service
等等。
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
}
}
}
回答by seb
Building on @Cornstalks answer to include a couple of useful features.
以@Cornstalks 答案为基础,包含一些有用的功能。
Extra features:
额外功能:
- introduced singleton pattern so you can do this anywhere in the application: AppLifecycleHandler.isApplicationVisible() and AppLifecycleHandler.isApplicationInForeground()
- added handling of duplicate events (see comments // take some action on change of visibility and // take some action on change of in foreground)
- 引入了单例模式,因此您可以在应用程序的任何位置执行此操作:AppLifecycleHandler.isApplicationVisible() 和 AppLifecycleHandler.isApplicationInForeground()
- 添加了对重复事件的处理(见评论 // 对可见性的变化采取一些行动,// 对前景的变化采取一些行动)
App.java
应用程序.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;
}
}