Ido*_*lon 386
几种方法可以检测您的应用程序是否在后台运行,但只有一种方法是完全可靠的:
正确的解决方案(学分去丹,CommonsWare和NeTeInStEiN)
使用自己的应用程序的轨道知名度Activity.onPause,Activity.onResume方法.将"可见性"状态存储在其他类中.好的选择是你自己实现的Applicationa或a Service(如果你想检查服务的活动可见性,这个解决方案还有一些变体).
示例
实现自定义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;
}
Run Code Online (Sandbox Code Playgroud)
注册您的应用程序类AndroidManifest.xml:
<application
android:name="your.app.package.MyApplication"
android:icon="@drawable/icon"
android:label="@string/app_name" >
Run Code Online (Sandbox Code Playgroud)
添加onPause和onResume每一个Activity项目(您可能为您的活动的共同祖先,如果你想,但如果你的活动已经从扩展MapActivity/ ListActivity等你仍然需要手工编写如下):
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
Run Code Online (Sandbox Code Playgroud)
更新
ActivityLifecycleCallbacks已在API级别14(Android 4.0)中添加.您可以使用它们来跟踪用户当前是否可以看到您的应用程序的活动.请查看 Cornstalks的回答,了解详情.
我以前提出以下解决方案的错误:
您可以检测当前前景/后台应用程序,使用
ActivityManager.getRunningAppProcesses()该应用程序返回RunningAppProcessInfo记录列表.要确定您的应用程序是否在前台检查RunningAppProcessInfo.importance字段中是否等于RunningAppProcessInfo.IMPORTANCE_FOREGROUNDwhile,RunningAppProcessInfo.processName则等于您的应用程序包名称.此外,如果您
ActivityManager.getRunningAppProcesses()从应用程序UI线程调用它,它将重新启动IMPORTANCE_FOREGROUND您的任务,无论它是否实际位于前台.在后台线程中调用它(例如viaAsyncTask),它将返回正确的结果.
虽然这个解决方案可能有效(并且它确实在大多数情况下都有效)但我强烈建议不要使用它.这就是原因.正如Dianne Hackborn所写:
这些API不适用于基于UI流程的应用程序,而是用于向用户显示正在运行的应用程序或任务管理器等.
是的,内存中有一个列表用于这些事情.但是,它是在另一个进程中关闭,由与您分开运行的线程管理,而不是您可以指望的事情(a)及时看到做出正确的决定,或者(b)在您返回时保持一致的图像.此外,关于"下一个"活动的内容的决定总是在切换发生的时刻完成,直到确切的点(活动状态被短暂锁定以进行切换),我们才实际上确切知道接下来会是什么.
此处的实施和全球行为不能保证在未来保持不变.
我希望在我在SO上发布答案之前已经阅读了这篇文章,但希望我承认错误并不算太晚.
在其中一个答案中提到的另一个错误解决方案
Droid-Fu库ActivityManager.getRunningTasks用于其isApplicationBroughtToBackground方法.请参阅上面的Dianne的评论,也不要使用该方法.
Cor*_*lks 259
user1269737的答案是正确的(谷歌/ Android批准)方式来做到这一点.去读他们的答案并给他们+1.
为了后人的缘故,我会在这里留下原来的答案.这是2012年最好的,但现在Android对此有适当的支持.
关键是使用ActivityLifecycleCallbacks(请注意,这需要Android API级别14(Android 4.0)).只需检查已停止活动的数量是否等于已启动活动的数量.如果它们相同,那么您的应用程序正在落后.如果有更多已启动的活动,则您的应用程序仍然可见.如果恢复活动多于暂停活动,则您的应用程序不仅可见,而且还在前台.您的活动可以有3种主要状态,然后:可见和前景,可见但不在前景,不可见而不在前景(即在后台).
关于这种方法的真正好处是,它不具备异步的问题getRunningTasks(),但你也不必修改每一个Activity在应用程序中设置警戒/解除警戒的东西onResumed()/ onPaused().它只是几行自包含的代码,它可以在整个应用程序中运行.此外,还不需要任何时髦的权限.
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;
}
*/
}
Run Code Online (Sandbox Code Playgroud)
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());
}
}
Run Code Online (Sandbox Code Playgroud)
@Mewzer已经问了一些关于这种方法的好问题,我想在这个答案中为每个人回答:
onStop()在低记忆情况下不会被调用; 这是一个问题吗?
不.文件onStop()说:
请注意,在内存不足的情况下,可能永远不会调用此方法,在这种情况下,系统没有足够的内存来保持活动进程在调用onPause()方法后运行.
这里的关键是"让你的活动进程保持运行 ......"如果达到这种低内存状态,你的进程实际上就被杀死了(不仅仅是你的活动).这意味着这种检查backgrounded-ness的方法仍然有效,因为a)如果您的进程被终止,您无法检查背景,b)如果您的进程再次启动(因为创建了新活动),该成员变量(无论是否为静态)MyLifecycleHandler将被重置为0.
这适用于配置更改吗?
默认情况下,没有.您必须在清单文件中显式设置configChanges=orientation|screensize(|使用您想要的任何其他内容)并处理配置更改,否则您的活动将被销毁并重新创建.如果您未设置此项,则将按此顺序调用您的活动的方法:onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume.如您所见,没有重叠(通常,当在两者之间切换时,两个活动非常短暂地重叠,这就是这种背景检测方法的工作原理).为了解决这个问题,您必须进行设置,configChanges以便不破坏您的活动.幸运的是,我必须configChanges已经在我的所有项目中设置,因为我的整个活动在屏幕旋转/调整大小时被破坏是不可取的,所以我从来没有发现这是有问题的.(感谢dpimka为此刷新我的记忆并纠正我!)
一个说明:
当我在这个答案中说"背景"时,我的意思是"你的应用程序不再可见".Android活动可见但不在前台(例如,如果有透明通知叠加层).这就是我更新这个答案以反映这一点的原因.
重要的是要知道Android在切换前景中没有任何东西的活动时会有一个奇怪的不确定时刻.出于这个原因,如果你在活动之间切换时检查你的应用程序是否在前台(在同一个应用程序中),你会被告知你不在前台(即使你的应用程序仍然是活动应用程序并且可见).
您可以在之后Activity的onPause()方法中检查您的应用是否在前台.请记住我刚才谈到的奇怪的状态. super.onPause()
您可以检查您的应用程序是可见的(即,如果它不是在后台)在你Activity的onStop()方法之后 super.onStop().
use*_*737 134
GOOGLE解决方案 - 不像以前的解决方案那样是黑客.使用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
}
}
Run Code Online (Sandbox Code Playgroud)
在app.gradle中
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
}
}
Run Code Online (Sandbox Code Playgroud)
net*_*ein 17
Idolon的答案是容易出错的,而且更复杂,虽然在这里重复检查android应用程序是否在前台?这里从后台任务或服务确定当前前台应用程序
有一个更简单的方法:
在所有活动扩展的BaseActivity上:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
Run Code Online (Sandbox Code Playgroud)
每当您需要检查您的应用程序活动是否在前台时,只需检查 isVisible() ;
要了解此方法,请检查并行活动生命周期的答案:活动并行生命周期
Kei*_*ati 16
启动支持库版本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
}
Run Code Online (Sandbox Code Playgroud)
然后只需查询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);
Run Code Online (Sandbox Code Playgroud)
Juo*_*nis 15
从Android API 16开始,有一种简单的方法可以检查应用是否在前台.它可能不是万无一失,但Android上没有任何方法是万无一失的.当您的服务从服务器接收更新并且必须决定是否显示通知时,此方法足够好用(因为如果UI是前台,用户将在没有通知的情况下注意到更新).
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Run Code Online (Sandbox Code Playgroud)
Men*_*ris 11
我尝试了使用Application.ActivityLifecycleCallbacks和许多其他的推荐解决方案,但它们没有按预期工作.感谢Sarge,我想出了一个非常简单直接的解决方案,我将在下面介绍.
解决方案的关键是理解如果我们有ActivityA和ActivityB,并且我们从ActivityA调用ActivityB(而不是调用
ActivityA.finish),那么onStart()将在 ActivityA 之前调用ActivityBonStop().
这也是主要的区别onStop(),并onPause()认为没有没提我读了文章.
因此,基于此Activity的生命周期行为,您可以简单地计算在您的程序中执行onStart()和onPause()调用的次数.请注意,每个 Activity程序的,你必须覆盖onStart()和onStop(),以增加/减少用于计数的静态变量.下面是实现此逻辑的代码.请注意,我正在使用扩展的类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--;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们的程序的每个活动,我们应该重写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();
}
Run Code Online (Sandbox Code Playgroud)
有了这个逻辑,有两种可能的情况:
stateCounter = 0 :已停止的数量与已启动的活动数量相等,这意味着应用程序正在后台运行.stateCounter > 0 :已启动的数量大于已停止的数量,这意味着应用程序正在前台运行.注意:stateCounter < 0意味着有更多停止的活动而不是启动,这是不可能的.如果您遇到这种情况,那么这意味着您没有按照自己的意愿增加/减少计数器.
你准备好了.您应该检查您的应用程序是否在内部onStop().
没有办法,没有你自己跟踪它,以确定你的任何活动是否可见.也许你应该考虑问一个新的StackOverflow问题,解释你试图通过用户体验实现什么,所以我们也许可以给你另外的实现思路.
您可以使用ComponentCallbacks2来检测应用程序是否在后台.BTW此回调仅适用于API级别14(冰淇淋三明治)及以上.
您将调用该方法:
public abstract void onTrimMemory (int level)
如果等级是ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN应用程序在后台.
您可以实现此接口的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
}
}
}
Run Code Online (Sandbox Code Playgroud)
我建议阅读此页面:http://developer.android.com/reference/android/app/Activity.html
onStop()简而言之,您的 Activity 在被调用后就不再可见。
| 归档时间: |
|
| 查看次数: |
203525 次 |
| 最近记录: |