如何检测 Android 应用程序何时进入后台并返回前台
我正在尝试编写一个应用程序,当它在一段时间后返回前台时,该应用程序会执行特定的操作。有没有办法检测应用程序何时发送到后台或带到前台?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我正在尝试编写一个应用程序,当它在一段时间后返回前台时,该应用程序会执行特定的操作。有没有办法检测应用程序何时发送到后台或带到前台?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(30)
2018 年:Android 通过生命周期组件原生支持此功能。
2018 年 3 月更新:现在有更好的解决方案。请参阅 ProcessLifecycleOwner。您将需要使用新的架构组件 1.1.0(目前最新),但它是专门为实现此目的而设计的。
在此答案中提供了一个简单的示例,但我写了一个示例应用 和 关于它的博客文章。
自从我在 2014 年写下这篇文章以来,出现了不同的解决方案。有些有效,有些被认为有效,但有缺陷(包括我的!),我们作为一个社区(Android)学会了承受后果,并为特殊情况编写了解决方法。
永远不要假设单个代码片段就是您正在寻找的解决方案,这种情况不太可能发生;更好的是,尝试理解它的作用以及为什么这样做。
正如这里所写,我从未真正使用过 MemoryBoss 类,它只是一段碰巧起作用的伪代码。
除非有充分的理由让您不使用新的架构组件(确实有一些组件,特别是如果您的目标是超旧的 api),那么就继续使用它们。它们远非完美,但 ComponentCallbacks2 也不是。
更新/注释(2015 年 11 月):人们提出了两条评论,首先是应该使用
>=
而不是==
因为文档指出您不应该检查确切的值。这对于大多数情况来说都很好,但请记住,如果您只关心当应用程序转到后台时做某事,则必须使用 == >并且还将其与其他解决方案(例如活动生命周期回调)结合起来,否则您可能无法获得您想要的效果。这个例子(这发生在我身上)是,如果您想在应用程序进入后台时使用密码屏幕锁定您的应用程序(例如 1Password,如果您熟悉的话),您可能会不小心如果您的内存不足并且突然测试>= TRIM_MEMORY
,请锁定您的应用,因为 Android 会触发LOW MEMORY
调用,并且该调用的内存容量高于您的内存。所以要小心你测试的方式/内容。此外,有些人询问如何检测您何时返回。
我能想到的最简单的方法解释如下,但由于有些人不熟悉它,所以我在这里添加一些伪代码。假设您的
类 BaseActivity extends Activity
中有YourApplication
和MemoryBoss
类(如果您没有,则需要创建一个)。我推荐 onStart 因为对话框可以暂停活动,所以我敢打赌,如果您所做的只是显示全屏对话框,您不希望您的应用程序认为“它进入了后台”,但您的情况可能会有所不同。
仅此而已。 if 块中的代码将仅执行一次,即使您转到另一个 Activity,新的 Activity(也
扩展了 BaseActivity
)也会报告wasInBackground< /code> 为
false
,因此它不会执行代码,直到调用onMemoryTrimmed
并将标志再次设置为 true。更新/注释(2015 年 4 月):在对这段代码进行所有复制和粘贴之前,请注意,我发现了几个实例,它可能不是 100% 可靠,并且必须组合起来 与其他方法配合以达到最佳效果。
值得注意的是,有两个已知的实例,
onTrimMemory
回调不能保证被执行:如果您的手机在您的应用程序可见时锁定屏幕(比如您的应用程序) nn 分钟后设备锁定),不会调用此回调(或并不总是),因为锁屏位于顶部,但您的应用程序仍在“运行”,尽管已被覆盖。
如果您的设备内存相对较低(并且处于内存压力下),操作系统似乎会忽略此调用并直接进入更关键的级别。
现在,根据您了解应用程序何时进入后台的重要性,您可能需要也可能不需要扩展此解决方案以及跟踪活动生命周期等。
只需牢记上述内容并拥有一支优秀的质量保证团队即可;)
更新结束
可能会晚一些,但冰淇淋三明治(API 14)及以上内容有一个可靠的方法 。
事实证明,当您的应用程序不再有可见的 UI 时,就会触发回调。您可以在自定义类中实现该回调,称为 ComponentCallbacks2< /a> (是的,有两个)。此回调仅在 API 级别 14(冰淇淋三明治)及更高版本中可用。
您基本上会调用该方法:
级别为 20 或更具体地说,
我一直在测试它,它总是有效,因为级别 20 只是一个“建议”,您可能想要释放一些资源,因为您的应用程序不再可用可见的。
引用官方文档:
当然,您应该实现它以实际执行它所说的操作(清除在特定时间内未使用的内存,清除一些一直未使用的集合等。可能性是无限的(请参阅官方文档以了解其他可能的< em>更关键的级别)。
但是,有趣的是,操作系统告诉您:嘿,您的应用程序进入了后台!
正是您首先想知道的。
这 确定你什么时候回来?
这很简单,我确信你有一个“BaseActivity”,所以你可以使用你的 onResume() 来标记你回来的事实。当您实际收到对上述 onTrimMemory 方法的调用时,就会说您没有回来。
如果活动正在恢复,您就不会返回。 100% 的情况下,如果用户再次返回到后面,您将收到另一个
onTrimMemory()
调用,您需要订阅您的 Activity(或者更好的是自定义类)。
保证您始终收到此消息的最简单方法是创建一个如下所示的简单类:
为了使用此类,请在您的应用程序实现中(您有一个,对吧?),执行以下操作
:您创建一个
Interface
,您可以向该if
添加一个else
并实现ComponentCallbacks
(不带 2) API 14 以下的任何内容。该回调只有onLowMemory()
方法,并且当您转到后台时不会被调用,但您应该使用它来修剪内存。现在启动您的应用程序并按主页。您的
onTrimMemory(final int level)
方法应该被调用(提示:添加日志记录)。最后一步是从回调中取消注册。最好的地方可能是应用程序的
onTerminate()
方法,但是,该方法不会在真实设备上调用:因此,除非您确实遇到不想再注册的情况,否则您可以安全地忽略它,因为您的进程无论如何都会在操作系统级别死亡。
如果您决定在某个时候取消注册(例如,如果您为应用程序提供清理和终止的关闭机制),您可以这样做:
就是这样。
2018: Android supports this natively through lifecycle components.
March 2018 UPDATE: There is now a better solution. See ProcessLifecycleOwner. You will need to use the new architecture components 1.1.0 (latest at this time) but it’s specifically designed to do this.
There’s a simple sample provided in this answer but I wrote a sample app and a blog post about it.
Ever since I wrote this back in 2014, different solutions arose. Some worked, some were thought to be working, but had flaws (including mine!) and we, as a community (Android) learned to live with the consequences and wrote workarounds for the special cases.
Never assume a single snippet of code is the solution you’re looking for, it’s unlikely the case; better yet, try to understand what it does and why it does it.
The
MemoryBoss
class was never actually used by me as written here, it was just a piece of pseudo code that happened to work.Unless there’s valid reason for you not to use the new architecture components (and there are some, especially if you target super old apis), then go ahead and use them. They are far from perfect, but neither were
ComponentCallbacks2
.UPDATE / NOTES (November 2015): People has been making two comments, first is that
>=
should be used instead of==
because the documentation states that you shouldn't check for exact values. This is fine for most cases, but bear in mind that if you only care about doing something when the app went to the background, you will have to use == and also combine it with another solution (like Activity Lifecycle callbacks), or you may not get your desired effect. The example (and this happened to me) is that if you want to lock your app with a password screen when it goes to the background (like 1Password if you're familiar with it), you may accidentally lock your app if you run low on memory and are suddenly testing for>= TRIM_MEMORY
, because Android will trigger aLOW MEMORY
call and that's higher than yours. So be careful how/what you test.Additionally, some people have asked about how to detect when you get back.
The simplest way I can think of is explained below, but since some people are unfamiliar with it, I'm adding some pseudo code right here. Assuming you have
YourApplication
and theMemoryBoss
classes, in yourclass BaseActivity extends Activity
(you will need to create one if you don't have one).I recommend onStart because Dialogs can pause an activity so I bet you don't want your app to think "it went to the background" if all you did was display a full screen dialog, but your mileage may vary.
And that's all. The code in the if block will only be executed once, even if you go to another activity, the new one (that also
extends BaseActivity
) will reportwasInBackground
isfalse
so it won't execute the code, untilonMemoryTrimmed
is called and the flag is set to true again.UPDATE / NOTES (April 2015): Before you go all Copy and Paste on this code, note that I have found a couple of instances where it may not be 100% reliable and must be combined with other methods to achieve the best results.
Notably, there are two known instances where the
onTrimMemory
call back is not guaranteed to be executed:If your phone locks the screen while your app is visible (say your device locks after nn minutes), this callback is not called (or not always) because the lockscreen is just on top, but your app is still "running" albeit covered.
If your device is relatively low on memory (and under memory stress), the Operating System seems to ignore this call and go straight to more critical levels.
Now, depending how important it's for you to know when your app went to the background, you may or may not need to extend this solution together with keeping track of the activity lifecycle and whatnot.
Just keep the above in mind and have a good QA team ;)
END OF UPDATE
It may be late but there's a reliable method in Ice Cream Sandwich (API 14) and Above.
Turns out that when your app has no more visible UI, a callback is triggered. The callback, which you can implement in a custom class, is called ComponentCallbacks2 (yes, with a two). This callback is only available in API Level 14 (Ice Cream Sandwich) and above.
You basically get a call to the method:
The Level is 20 or more specifically
I've been testing this and it always works, because level 20 is just a "suggestion" that you might want to release some resources since your app is no longer visible.
To quote the official docs:
Of course, you should implement this to actually do what it says (purge memory that hasn't been used in certain time, clear some collections that have been sitting unused, etc. The possibilities are endless (see the official docs for other possible more critical levels).
But, the interesting thing, is that the OS is telling you: HEY, your app went to the background!
Which is exactly what you wanted to know in the first place.
How do you determine when you got back?
Well that's easy, I'm sure you have a "BaseActivity" so you can use your onResume() to flag the fact that you're back. Because the only time you will be saying you're not back is when you actually receive a call to the above
onTrimMemory
method.It works. You don't get false positives. If an activity is resuming, you're back, 100% of the times. If the user goes to the back again, you get another
onTrimMemory()
call.You need to suscribe your Activities (or better yet, a custom class).
The easiest way to guarantee that you always receive this is to create a simple class like this:
In order to use this, in your Application implementation (you have one, RIGHT?), do something like:
If you create an
Interface
you could add anelse
to thatif
and implementComponentCallbacks
(without the 2) used in anything below API 14. That callback only has theonLowMemory()
method and does not get called when you go to the background, but you should use it to trim memory.Now launch your App and press home. Your
onTrimMemory(final int level)
method should be called (hint: add logging).The last step is to unregister from the callback. Probably the best place is the
onTerminate()
method of your App, but, that method doesn't get called on a real device:So unless you really have a situation where you no longer want to be registered, you can safety ignore it, since your process is dying at OS level anyway.
If you decide to unregister at some point (if you, for example, provide a shutdown mechanism for your app to clean up and die), you can do:
And that's it.
更新 2021 年 11 月
实际设置如下
依赖项
原始答案
ProcessLifecycleOwner
似乎也是一个有前途的解决方案。实现可以像根据
源代码,当前延迟值为
700ms
。使用此功能还需要
依赖项
:UPDATE November 2021
Actual setup is as follows
Dependencies
ORIGINAL ANSWER
ProcessLifecycleOwner
seems to be a promising solution also.An implementation can be as simple as
According to source code, current delay value is
700ms
.Also using this feature requires the
dependencies
:这是我设法解决这个问题的方法。它的工作前提是,使用活动转换之间的时间参考很可能提供足够的证据来证明应用程序是否已“后台运行”。
首先,我使用了一个 android.app.Application 实例(我们称之为 MyApplication),它有一个 Timer、一个 TimerTask、一个常量来表示从一个活动转换到另一个活动可以合理地花费的最大毫秒数(我去了值为 2s),以及一个布尔值来指示应用程序是否“在后台”:
该应用程序还提供了两种用于启动和停止计时器/任务的方法:
该解决方案的最后一部分是添加一个调用从所有活动的 onResume() 和 onPause() 事件中的每个方法,或者最好是在所有具体活动继承的基础活动中:
因此,当用户只是在您的活动之间导航时在应用程序中,离开活动的 onPause() 会启动计时器,但几乎立即进入的新活动会在达到最大转换时间之前取消计时器。所以wasInBackground将是false。
另一方面,当 Activity 从启动器进入前台、设备唤醒、结束电话通话等时,很可能计时器任务在此事件之前执行,因此设置了 wasInBackground为真。
Here's how I've managed to solve this. It works on the premise that using a time reference between activity transitions will most likely provide adequate evidence that an app has been "backgrounded" or not.
First, I've used an android.app.Application instance (let's call it MyApplication) which has a Timer, a TimerTask, a constant to represent the maximum number of milliseconds that the transition from one activity to another could reasonably take (I went with a value of 2s), and a boolean to indicate whether or not the app was "in the background":
The application also provides two methods for starting and stopping the timer/task:
The last piece of this solution is to add a call to each of these methods from the onResume() and onPause() events of all activities or, preferably, in a base Activity from which all of your concrete Activities inherit:
So in the case when the user is simply navigating between the activities of your app, the onPause() of the departing activity starts the timer, but almost immediately the new activity being entered cancels the timer before it can reach the max transition time. And so wasInBackground would be false.
On the other hand when an Activity comes to the foreground from the Launcher, device wake up, end phone call, etc., more than likely the timer task executed prior to this event, and thus wasInBackground was set to true.
编辑:新的架构组件带来了一些有前途的东西: ProcessLifecycleOwner,参见@vokilam的回答
根据Google I/O 演讲:
是的。我知道很难相信这个简单的解决方案有效,因为我们这里有很多奇怪的解决方案。
但还有希望。
Edit: the new architecture components brought something promising: ProcessLifecycleOwner, see @vokilam's answer
The actual solution according to a Google I/O talk:
Yes. I know it's hard to believe this simple solution works since we have so many weird solutions here.
But there is hope.
当应用程序进入后台并再次进入前台时,将调用
onPause()
和onResume()
方法。然而,它们也会在应用程序首次启动时和被终止之前被调用。您可以在Activity中阅读更多内容。没有任何直接的方法可以在后台或前台获取应用程序状态,但即使我也遇到过这个问题,并通过
onWindowFocusChanged
和onStop
找到了解决方案。有关更多详细信息,请查看此处 Android :在没有 getRunningTasks 或 getRunningAppProcesses 的情况下检测 Android 应用何时进入后台并返回前台的解决方案。
The
onPause()
andonResume()
methods are called when the application is brought to the background and into the foreground again. However, they are also called when the application is started for the first time and before it is killed. You can read more in Activity.There isn't any direct approach to get the application status while in the background or foreground, but even I have faced this issue and found the solution with
onWindowFocusChanged
andonStop
.For more details check here Android: Solution to detect when an Android app goes to the background and come back to the foreground without getRunningTasks or getRunningAppProcesses.
根据 Martín Marconcinis 的回答(谢谢!)我终于找到了一个可靠的(而且非常简单)的解决方案。
然后将其添加到 Application 类的 onCreate() 中
Based on Martín Marconcinis answer (thanks!) I finally found a reliable (and very simple) solution.
Then add this to your onCreate() of your Application class
我们使用这种方法。它看起来太简单了,无法工作,但它在我们的应用程序中经过了充分测试,实际上在所有情况下都表现得非常好,包括通过“主页”按钮、“返回”按钮或屏幕锁定后进入主屏幕。尝试一下。
想法是,当在前台时,Android 总是在停止前一个活动之前启动新的活动。不能保证这一点,但这就是它的工作原理。顺便说一句,Flurry 似乎使用相同的逻辑(只是猜测,我没有检查,但它挂钩相同的事件)。
编辑:根据评论,我们还在更高版本的代码中移至 onStart() 。另外,我添加了超级调用,这是我最初的帖子中所缺少的,因为这更多的是一个概念而不是工作代码。
We use this method. It looks too simple to work, but it was well-tested in our app and in fact works surprisingly well in all cases, including going to home screen by "home" button, by "return" button, or after screen lock. Give it a try.
Idea is, when in foreground, Android always starts new activity just before stopping previous one. That's not guaranteed, but that's how it works. BTW, Flurry seems to use the same logic (just a guess, I didn't check that, but it hooks at the same events).
Edit: as per comments, we also moved to onStart() in later versions of the code. Also, I'm adding super calls, which were missing from my initial post, because this was more of a concept than a working code.
如果您的应用程序由多个活动和/或堆叠活动(如选项卡栏小部件)组成,则覆盖 onPause() 和 onResume() 将不起作用。即,当开始一项新活动时,当前活动将在创建新活动之前暂停。完成(使用“后退”按钮)活动时也是如此。
我发现两种方法似乎可以按需要工作。
第一个需要 GET_TASKS 权限,由一个简单的方法组成,该方法通过比较包名称来检查设备上运行最多的活动是否属于应用程序:
该方法可以在 Droid-Fu(现在称为 Ignition)框架中找到。
我自己实现的第二种方法不需要 GET_TASKS 权限,这很好。相反,它的实施起来稍微复杂一些。
在 MainApplication 类中,您有一个变量用于跟踪应用程序中正在运行的活动的数量。在每个活动的 onResume() 中,您增加变量,在 onPause() 中,您减少变量。
当正在运行的活动数量达到 0 时,如果满足以下条件,则应用程序将进入后台:
当您可以检测到应用程序已退出后台时,也可以轻松检测到它何时返回前台。
If your app consists of multiple activites and/or stacked activites like a tab bar widget, then overriding onPause() and onResume() will not work. I.e when starting a new activity the current activites will get paused before the new one is created. The same applies when finishing (using "back" button) an activity.
I've found two methods that seem to work as wanted.
The first one requires the GET_TASKS permission and consists of a simple method that checks if the top running activity on the device belongs to application, by comparing package names:
This method was found in the Droid-Fu (now called Ignition) framework.
The second method that I've implemented my self does not require the GET_TASKS permission, which is good. Instead it is a little more complicated to implement.
In you MainApplication class you have a variable that tracks number of running activities in your application. In onResume() for each activity you increase the variable and in onPause() you decrease it.
When the number of running activities reaches 0, the application is put into background IF the following conditions are true:
When you can detect that the application has resigned to the background it is easy detect when it is brought back to foreground as well.
创建一个扩展
Application
的类。然后我们可以在其中使用它的重写方法onTrimMemory()
。要检测应用程序是否进入后台,我们将使用:
Create a class that extends
Application
. Then in it we can use its override method,onTrimMemory()
.To detect if the application went to the background, we will use:
考虑使用 onUserLeaveHint。仅当您的应用程序进入后台时才会调用此函数。 onPause 将有特殊情况需要处理,因为它可能因其他原因而被调用;例如,如果用户在您的应用程序中打开另一个 Activity(例如您的设置页面),则您的主 Activity 的 onPause 方法将被调用,即使它们仍在您的应用程序中;当您可以简单地使用 onUserLeaveHint 回调来执行您所要求的操作时,跟踪正在发生的事情会导致错误。
当调用 UserLeaveHint 时,您可以将布尔 inBackground 标志设置为 true。当调用 onResume 时,如果设置了 inBackground 标志,则仅假设您返回前台。这是因为如果用户只是在您的设置菜单中并且从未离开过应用程序,onResume 也会在您的主要活动中被调用。
请记住,如果用户在设置屏幕中点击主页按钮,则 onUserLeaveHint 将在您的设置活动中调用,而当用户返回时, onResume 将在您的设置活动中调用。如果您的主要活动中只有此检测代码,您将错过此用例。要在所有活动中使用此代码而不重复代码,请拥有一个扩展 Activity 的抽象活动类,并将通用代码放入其中。然后你的每一个活动都可以扩展这个抽象活动。
例如:
Consider using onUserLeaveHint. This will only be called when your app goes into the background. onPause will have corner cases to handle, since it can be called for other reasons; for example if the user opens another activity in your app such as your settings page, your main activity's onPause method will be called even though they are still in your app; tracking what is going in will lead to bugs when you can instead simply use the onUserLeaveHint callback which does what you are asking.
When on UserLeaveHint is called, you can set a boolean inBackground flag to true. When onResume is called, only assume you came back into the foreground if the inBackground flag is set. This is because onResume will also be called on your main activity if the user was just in your settings menu and never left the app.
Remember that if the user hits the home button while in your settings screen, onUserLeaveHint will be called in your settings activity, and when they return onResume will be called in your settings activity. If you only have this detection code in your main activity you will miss this use case. To have this code in all your activities without duplicating code, have an abstract activity class which extends Activity, and put your common code in it. Then each activity you have can extend this abstract activity.
For example:
android.arch.lifecycle 包提供了类和接口,可让您构建生命周期感知组件
您的应用程序应该实现 LifecycleObserver 接口:
为此,您需要将此依赖项添加到您的 build.gradle 文件中:
根据 Google 的建议,您应该尽量减少在 Activity 的生命周期方法中执行的代码:
您可以在这里阅读更多内容:
https://developer.android.com/topic/libraries/architecture/lifecycle
The android.arch.lifecycle package provides classes and interfaces that let you build lifecycle-aware components
Your application should implement the LifecycleObserver interface:
To do that, you need to add this dependency to your build.gradle file:
As recommended by Google, you should minimize the code executed in the lifecycle methods of activities:
You can read more here:
https://developer.android.com/topic/libraries/architecture/lifecycle
ActivityLifecycleCallbacks 可能很有趣,但没有很好的文档记录。
不过,如果您调用 registerActivityLifecycleCallbacks()您应该能够在创建、销毁 Activity 等时获得回调。您可以调用 getComponentName() 代表活动。
ActivityLifecycleCallbacks might be of interest, but it isn't well documented.
Though, if you call registerActivityLifecycleCallbacks() you should be able to get callbacks for when Activities are created, destroyed, etc. You can call getComponentName() for the Activity.
在您的应用程序中添加回调并以如下方式检查根活动:
In your Application add the callback and check for root activity in a way like this:
您可以使用 ProcessLifecycleOwner 将生命周期观察器附加到它。
然后在您的 Application 类的
onCreate()
上调用它:通过它,您将能够捕获
ON_PAUSE
和ON_STOP
的事件当您的应用程序进入后台时发生的情况。You can use the ProcessLifecycleOwner attaching a lifecycle observer to it.
then on the
onCreate()
of your Application class you call this:with this you will be able to capture the events of
ON_PAUSE
andON_STOP
of your application that happen when it goes in background.我在 Github 上创建了一个项目 app-foreground-background-listen
创建一个 BaseActivity对于应用程序中的所有 Activity。
现在使用这个 BaseActivity 作为所有 Activity 的超类,就像 MainActivity 扩展 BaseActivity 一样,当您启动应用程序时,将调用 onAppStart ,当应用程序从任何屏幕进入后台时,将调用 onAppPause() 。
I have created a project on Github app-foreground-background-listen
Create a BaseActivity for all Activity in your application.
Now use this BaseActivity as a super class of all your Activity like MainActivity extends BaseActivity and onAppStart will be called when you start your application and onAppPause() will be called when the application goes the background from any screen.
使用 ProcessLifecycleOwner
添加这些依赖项< /strong>
在 Kotlin 中:
然后在您的基本活动中:
请参阅我关于此主题的文章:
https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48
This is pretty easy with ProcessLifecycleOwner
Add these dependencies
In Kotlin:
Then in your base activity:
See my article on this topic:
https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48
没有简单的生命周期方法可以告诉您整个应用程序何时进入后台/前台。
我已经用简单的方法做到了这一点。按照以下说明检测应用程序后台/前台阶段。
通过一些解决方法,这是可能的。在这里,ActivityLifecycleCallbacks 来救援。让我逐步介绍一下。
首先,创建一个扩展 android.app.Application 并实现 ActivityLifecycleCallbacks 接口的类。在Application.onCreate()中,注册回调。
在清单中注册“App”类,如下所示,。
当应用处于前台时,至少有一个处于启动状态的 Activity;当应用处于后台时,不会有处于启动状态的 Activity。
在“App”类中声明如下2个变量。
activityReferences
将保留处于已启动状态的活动数量计数。isActivityChangingConfigurations
是一个标志,指示当前 Activity 是否正在经历配置更改(如方向切换)。使用以下代码,您可以检测应用程序是否进入前台。
>
<前><代码>@Override
公共无效onActivityStarted(活动活动){
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// 应用程序进入前台
}
}
这是检测应用程序是否进入后台的方法。
<前><代码>@Override
公共无效onActivityStopped(活动活动){
isActivityChangingConfigurations = Activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// 应用程序进入后台
}
}
工作原理:
这是通过按顺序调用 Lifecycle 方法的方式完成的一个小技巧。让我演练一个场景。
假设用户启动App并启动Launcher Activity A。生命周期调用将是,
现在 Activity A 启动 Activity B。
然后用户从 Activity B 导航回来,
然后用户按下主页按钮,
如果用户从 Activity B 按下 Home 按钮而不是 Back 按钮,仍然是相同的,activityReferences 将是<代码>0。因此,我们可以检测到App进入后台。
那么,
isActivityChangingConfigurations
的作用是什么?在上面的场景中,假设 Activity B 改变了方向。回调顺序将是,这就是为什么我们要额外检查
isActivityChangingConfigurations
以避免 Activity 进行配置更改时出现这种情况。There are no straightforward lifecycle methods to tell you when the whole Application goes background/foreground.
I have done this with simple way. Follow the below instructions to detect application background/foreground phase.
With a little workaround, it is possible. Here, ActivityLifecycleCallbacks comes to the rescue. Let me walk through step-by-step.
First, create a class that extends the android.app.Application and implements the ActivityLifecycleCallbacks interface. In the Application.onCreate(), register the callback.
Register the “App” class in the Manifest as below,
<application android:name=".App"
.There will be at least one Activity in the started state when the app is in the foreground and there will be no Activity in the started state when the app is in the background.
Declare 2 variables as below in the “App” class.
activityReferences
will keep the count of number of activities in the started state.isActivityChangingConfigurations
is a flag to indicate if the current Activity is going through configuration change like an orientation switch.Using the following code you can detect if the App comes foreground.
This is how to detect if the App goes background.
How it works:
This is a little trick done with the way the Lifecycle methods are called in sequence. Let me walkthrough a scenario.
Assume that the user launches the App and the Launcher Activity A is launched. The Lifecycle calls will be,
Now Activity A starts Activity B.
Then the user navigates back from Activity B,
Then the user presses Home button,
In case, if the user presses Home button from Activity B instead of Back button, still it will be the same and activityReferences will be
0
. Hence, we can detect as the App entering Background.So, what’s the role of
isActivityChangingConfigurations
? In the above scenario, suppose the Activity B changes the orientation. The callback sequence will be,That’s why we have an additional check of
isActivityChangingConfigurations
to avoid the scenario when the Activity is going through the Configuration changes.您可以使用:
区分新启动和重新启动。
You can use:
To differ between new starts and restarts.
编辑2:我下面写的内容实际上不会起作用。 Google 拒绝了包含对 ActivityManager.getRunningTasks() 调用的应用程序。从 文档 可以明显看出, API 仅用于调试和开发目的。一旦我有时间用一个使用计时器并且几乎同样好的新方案更新下面的 GitHub 项目,我就会更新这篇文章。
编辑1:我写了一篇博客文章 并创建了一个简单的 GitHub 存储库,使这一切变得非常简单。
接受的和评价最高的答案都不是真正的最佳方法。评分最高的答案的 isApplicationBroughtToBackground() 实现不能处理应用程序的主 Activity 屈服于同一应用程序中定义的活动的情况,但它具有不同的 Java 包。我想出了一种在这种情况下可行的方法。
在 onPause() 中调用此函数,它会告诉您应用程序是否由于另一个应用程序已启动或用户按下了主页按钮而进入后台。
Edit 2: What I've written below will not actually work. Google has rejected an app that includes a call to ActivityManager.getRunningTasks(). From the documentation, it is apparent that this API is for debugging and development purposes only. I'll be updating this post as soon as I have time to update the GitHub project below with a new scheme that uses timers and is almost as good.
Edit 1: I've written up a blog post and created a simple GitHub repository to make this really easy.
The accepted and top rated answer are both not really the best approach. The top rated answer's implementation of isApplicationBroughtToBackground() does not handle the situation where the Application's main Activity is yielding to an Activity that is defined in the same Application, but it has a different Java package. I came up with a way to do this that will work in that case.
Call this in onPause(), and it will tell you if your application is going into the background because another application has started, or the user has pressed the home button.
您可以简单地在应用程序类中调用此方法
Lifecycle.Event
将简单地返回应用程序的状态,它将返回 ON_PAUSE & ON_STOP 当应用程序进入后台时
并将返回 ON_START &当应用程序到达前台时 ON_RESUME
you can simply call this method in your application class
Lifecycle.Event
will simply return the state of the applicationit will return ON_PAUSE & ON_STOP when the app goes to background
and will return ON_START & ON_RESUME when the app comes to the foreground
我找到了一个很好的方法来检测应用程序是否进入前台或后台。
这是我的代码。
希望这对您有帮助。
}
I found a good method to detect application whether enter foreground or background.
Here is my code.
Hope this help you.
}
我将其与 Google Analytics EasyTracker 一起使用,并且它有效。它可以扩展为使用简单的整数来完成您想要的操作。
I was using this with Google Analytics EasyTracker, and it worked. It could be extended to do what you seek using a simple integer.
由于我没有找到任何方法,也可以在不检查时间戳的情况下处理旋转,所以我想我也分享了我们现在如何在我们的应用程序中执行此操作。
这个答案的唯一补充 https://stackoverflow.com/a/42679191/5119746 是,我们还采用方向考虑。
然后,对于回调,我们首先有简历:
和 onActivityStopped:
然后,添加: 检查方向变化:
就是这样。希望这对某人有帮助:)
Since I did not find any approach, which also handles rotation without checking time stamps, I thought I also share how we now do it in our app.
The only addition to this answer https://stackoverflow.com/a/42679191/5119746 is, that we also take the orientation into consideration.
Then, for the callbacks we have the resume first:
And onActivityStopped:
And then, here comes the addition: Checking for orientation changes:
That's it. Hope this helps someone :)
此处正确答案
创建名为 MyApp 的类,如下所示:
然后,在您想要的任何地方(最好在应用程序中启动第一个活动)添加以下代码:
完成!现在,当应用程序在后台运行时,我们会收到日志
status : we are out
当我们进入应用程序时,我们会收到日志
status : we are out
Correct Answer here
Create class with name MyApp like below:
Then, everywhere you want (better first activity launched in app), add the code below:
Done! Now when the app is in the background, we get log
status : we are out
and when we go in app, we get log
status : we are out
这是通过使用去抖动逻辑来确保我们不会获得连续的背景/前景事件的解决方案。因此,它总是反映背景/前景的稳定状态。
只需创建一个 AppLifecycleObserver 实例:
不要忘记添加适当的 版本:
Here is the solution that by using a debouncing logic, makes sure we are not getting consecutive background/foreground events. So, it always reflects a stable state of backgrounding/foregrounding.
Just needs to create an instance of
AppLifecycleObserver
:Don't forget to add a proper version of the dependency:
LifecycleObserver
已弃用。使用DefaultLifecycleObserver
代替:依赖项:
LifecycleObserver
is deprecated. UseDefaultLifecycleObserver
instead:Dependencies:
我所做的是确保所有应用内活动均通过
startActivityForResult
启动,然后检查 onActivityResult 是否在 onResume 之前调用。如果不是,则意味着我们刚刚从应用程序之外的某个地方返回。What I did is make sure that all in-app activities are launched with
startActivityForResult
then checking if onActivityResult was called before onResume. If it wasn't, it means we just returned from somewhere outside our app.我的解决方案受到@d60402的答案的启发,并且还依赖于时间窗口,但不使用
Timer
:其中
SingletonApplication
是Application
的扩展代码>类:My solution was inspired by @d60402's answer and also relies on a time-window, but not using the
Timer
:where the
SingletonApplication
is an extension ofApplication
class:我知道有点晚了,但我认为所有这些答案确实存在一些问题,而我按照下面的方式做了,效果很完美。
创建一个像这样的活动生命周期回调:
然后将其注册到您的应用程序类上,如下所示:
i know its a little late but i think all these answers do have some problems while i did it like below and that works perfect.
create a activity life cycle callback like this:
and just register it on your application class like below:
这似乎是 Android 中最复杂的问题之一,因为(截至撰写本文时)Android 没有与 iOS 等效的
applicationDidEnterBackground()
或applicationWillEnterForeground()
回调。我使用了由 AppState 库 /jenzz" rel="nofollow noreferrer">@jenzz。事实证明,这正是我所需要的,特别是因为我的应用程序有多个活动,所以简单地检查活动上的
onStart()
或onStop()
并不会减少它。首先,我将这些依赖项添加到 gradle:
然后,将这些行添加到代码中的适当位置是一个简单的问题:
根据您订阅可观察对象的方式,您可能必须取消订阅以避免内存泄漏。更多信息请参见 github 页面。
This appears to be one of the most complicated questions in Android since (as of this writing) Android doesn't have iOS equivalents of
applicationDidEnterBackground()
orapplicationWillEnterForeground()
callbacks. I used an AppState Library that was put together by @jenzz.It turned out this is exactly what I needed, especially because my app had multiple activities so simply checking
onStart()
oronStop()
on an activity wasn't going to cut it.First I added these dependencies to gradle:
Then it was a simple matter of adding these lines to an appropriate place in your code:
Depending on how you subscribe to the observable, you may have to unsubscribe from it to avoid memory leaks. Again more info on the github page.