通过后台,我的意思是用户当前无法看到应用程序的任何活动吗?
答案 0 :(得分:384)
有几种方法可以检测您的应用程序是否在后台运行,但只有一种方法是完全可靠的:
正确的解决方案(积分转至Dan,CommonsWare和NeTeInStEiN)
使用Activity.onPause
,Activity.onResume
方法自行跟踪应用程序的可见性。将“可见性”状态存储在其他类中。如果您想检查服务的活动可见性,那么您可以选择自己实施Application
或Service
(此解决方案还有a few variations。)
的 实施例 强>
实现自定义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' answer了解详细信息。
错误的
我曾经建议以下解决方案:
您可以使用
ActivityManager.getRunningAppProcesses()
检测当前的前台/后台应用程序,该应用程序返回RunningAppProcessInfo
条记录的列表。要确定您的应用程序是否位于前台,请检查RunningAppProcessInfo.importance
字段是否与RunningAppProcessInfo.IMPORTANCE_FOREGROUND
相等,而RunningAppProcessInfo.processName
等于您的应用程序包名称。此外,如果您从应用程序UI线程调用
ActivityManager.getRunningAppProcesses()
,无论它是否实际位于前台,它都将为您的任务返回重要性IMPORTANCE_FOREGROUND
。在后台线程中调用它(例如通过AsyncTask
),它将返回正确的结果。
虽然这个解决方案可能有效(并且它确实在大部分时间都有效)但我强烈建议不要使用它。这就是原因。 As Dianne Hackborn wrote:
这些API不适用于基于UI流程的应用程序,而是用于向用户显示正在运行的应用程序或任务管理器等。
是的,这些东西在内存中保留了一个列表。但是,它是在另一个进程中关闭的,由与你的线程分开运行的线程管理,而不是你可以依赖的东西(a)及时看到做出正确的决定,或者(b)在你返回时有一致的画面。此外,关于“下一个”活动的内容的决定总是在切换发生的时刻完成,直到确切的点(活动状态被短暂锁定以进行切换),我们才实际上确切知道接下来会发生什么。
此处的实施和全球行为不能保证在未来保持不变。
我希望在我在SO上发布答案之前已经阅读了这篇文章,但希望我承认错误并不会太迟。
另一个错误的解决方案
其中一个答案中提到的Droid-Fu库使用ActivityManager.getRunningTasks
作为isApplicationBroughtToBackground
方法。请参阅上面的Dianne的评论,也不要使用该方法。
答案 1 :(得分:255)
<强> user1269737's answer is the proper (Google/Android approved) way to do this。去阅读他们的答案并给他们+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;
}
*/
}
<强> 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已经就这个方法提出了一些很好的问题,我想在这个答案中为每个人回答:
在低内存情况下不会调用 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()
方法中检查您的应用是否位于前台。请记住我刚才谈到的奇怪的状态。
您可以在<{em> Activity
之后的onStop()
super.onStop()
方法中查看您的应用是否可见(即,它是否在后台)。< / p>
答案 2 :(得分:81)
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
}
}
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' }
}
}
您可以在此处详细了解与生命周期相关的架构组件 - https://developer.android.com/topic/libraries/architecture/lifecycle
答案 3 :(得分:17)
Idolon的答案容易出错,而且更复杂,在此重复check android application is in foreground or not?和Determining the current foreground application from a background task or service
有一种更简单的方法:
在所有活动扩展的 BaseActivity上:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
每当您需要检查是否有任何应用程序活动在前台时,请检查 isVisible()
;
要了解此方法,请查看并排活动生命周期的答案:Activity side-by-side lifecycle
答案 4 :(得分:13)
从Android API 16开始,有一种简单的方法可以检查应用是否在前台。它可能不是万无一失,但Android上没有任何方法是万无一失的。当您的服务从服务器接收更新并且必须决定是否显示通知时,此方法足够好用(因为如果UI是前台,用户将注意到更新而不通知)。
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
答案 5 :(得分:11)
我尝试了使用Application.ActivityLifecycleCallbacks和其他许多其他方法的推荐解决方案,但它们没有按预期工作。感谢Sarge,我提出了一个非常简单明了的解决方案,我将在下面介绍。
解决方案的关键是理解如果我们有ActivityA和ActivityB,并且我们从ActivityA调用ActivityB(而不是调用
ActivityA.finish
),那么ActivityB&#39;onStart()
将会被称为之前 ActivityAonStop()
。
这也是onStop()
和onPause()
之间的主要差异,在我读过的文章中没有提到过。
因此,根据此活动的生命周期行为,您可以简单地计算在您的计划中调用onStart()
和onPause()
的次数。请注意,对于程序的每个 Activity
,必须覆盖onStart()
和onStop()
,以便递增/递减用于计数的静态变量。下面是实现此逻辑的代码。请注意,我使用的是扩展Application
的类,所以不要忘记在应用程序标记Manifest.xml
内的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--;
}
}
现在在我们程序的每个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();
}
有了这个逻辑,有两种可能的情况:
stateCounter = 0
:已停止的数量与已启动的活动数量相等,这意味着应用程序正在后台运行。stateCounter > 0
:已启动的数量大于已停止的数量,这意味着应用程序正在前台运行。注意:stateCounter < 0
意味着有更多停止的活动而不是启动,这是不可能的。如果你遇到这种情况,那就意味着你没有按照你的意愿增加/减少计数器。
你准备好了。您应该检查您的应用程序是否位于onStop()
内的背景中。
答案 6 :(得分:10)
您可以使用ProcessLifecycleOwner开始使用支持库版本26,只需像描述的here一样将其添加到依赖项中即可,例如:
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
}
然后只要需要查询应用状态就可以查询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);
答案 7 :(得分:8)
如果您没有亲自跟踪,则无法确定您的任何活动是否可见。也许您应该考虑提出一个新的StackOverflow问题,解释您尝试从用户体验中获得的内容,以便我们为您提供其他实现方案。
答案 8 :(得分:5)
您可以使用ComponentCallbacks2来检测应用是否在后台。顺便说一句,这个回调在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
}
}
}
答案 9 :(得分:4)
在@Cornstalks的基础上回答包含一些有用的功能。
额外功能:
App.java
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
}
}
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 :(得分:3)
我提出的最佳解决方案是使用计时器。
你已经在onPause()中启动了一个定时器,并在onResume()中取消了相同的定时器,有一个Timer实例(通常在Application类中定义)。计时器本身设置为在2秒后(或您认为合适的任何间隔)运行Runnable,当计时器触发时,您设置一个标记应用程序在后台的标志。
在取消计时器之前的onResume()方法中,您可以查询后台标志以执行任何启动操作(例如,开始下载或启用位置服务)。
此解决方案允许您在后台堆栈上有多个活动,并且不需要任何权限来实现。
如果您使用事件总线,此解决方案也可以正常工作,因为您的计时器可以简单地触发事件,并且应用的各个部分都可以做出相应的响应。
答案 11 :(得分:3)
如果您启用开发者设置&#34;请勿保持活动状态&#34; - 仅检查创建的活动的数量是不够的。您还必须检查 isSaveInstanceState 。我的自定义方法 isApplicationRunning()检查是android app正在运行:
这是我的工作代码:
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) { }
}
答案 12 :(得分:2)
我自己实现了ActivityLifecycleCallbacks。我正在使用SherlockActivity,但是对于普通的Activity类可能会有效。
首先,我正在创建一个界面,其中包含跟踪活动生命周期的所有方法:
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);
}
其次,我在我的应用程序类中实现了这个接口:
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());
}
}
第三,我正在创建一个从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);
}
}
第四,所有从SherlockActivity扩展的类,我替换为MySherlockActivity:
public class MainActivity extends MySherlockActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
现在,在logcat中,您将看到在MyApplication中进行的Interface实现中编写的日志。
答案 13 :(得分:2)
为了搭载CommonsWare和Key所说的内容,你可以扩展Application类,并让你的所有活动在onPause / onResume方法上调用它。这将允许您知道哪些活动可见,但这可能会更好地处理。
你能详细说明你的想法吗?当你说在后台运行时,你是说只是让你的应用程序仍在内存中,即使它当前不在屏幕上?您是否考虑过使用服务作为一种更持久的方式来管理您的应用程序?#/ p>
答案 14 :(得分:1)
唯一正确的解决方案:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
MyApp.mainActivity = this;
super.onCreate(savedInstanceState);
...
}
public class MyApp extends Application implements LifecycleObserver {
public static MainActivity mainActivity = null;
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onAppBackgrounded() {
// app in background
if (mainActivity != null) {
...
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onAppForegrounded() {
// app in foreground
if (mainActivity != null) {
...
}
}
}
答案 15 :(得分:1)
系统区分前景和后台应用。 (出于服务限制的目的,背景的定义与内存管理所使用的定义不同;应用程序可能在后台与内存管理相关,但在前景中与其能力相关启动服务。)如果满足以下任何条件,则认为应用程序位于前台:
如果这些条件都不成立,则认为应用程序在后台。
答案 16 :(得分:1)
由于尚未提及,我建议读者通过ProcessLifecycleOwner探索Android Architecture components
答案 17 :(得分:1)
当Dialog位于其上方时,活动会暂停,因此所有推荐的解决方案都是半解决方案。您还需要为对话框创建钩子。
答案 18 :(得分:0)
如何使用getApplicationState()。isInForeground()?
答案 19 :(得分:0)
我建议您阅读此页面:http://developer.android.com/reference/android/app/Activity.html
简而言之,在调用onStop()
后,您的活动将不再可见。
答案 20 :(得分:0)
我认为这个问题应该更清楚。什么时候?哪里?如果您的应用程序处于后台,您想要知道的具体情况是什么?
我只是按照自己的方式介绍我的解决方案
我通过在我的应用中的每个活动的RunningAppProcessInfo
方法中使用onStop
类的字段“重要性”来完成此操作,这可以通过为其他活动提供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;
}
答案 21 :(得分:0)
您应该使用共享首选项来存储属性,并使用您活动中的service binding对其进行操作。如果你只使用绑定,(永远不会使用startService),那么你的服务只有在你绑定它时才会运行(绑定onResume和unbind onPause),这会使它只在前台运行,如果你想继续工作背景,你可以使用常规的开始停止服务。
答案 22 :(得分:0)
请参阅onActivityDestroyed函数中的注释。
适用于SDK目标版本14&gt; :
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++;
}
}
答案 23 :(得分:0)
在我看来,许多答案会引入大量代码并带来大量复杂性和不可读性。
当人们询问如何在Service
和Activity
之间进行通信时,我通常建议使用LocalBroadcastManager。
<强>为什么吗
好吧,引用文档:
您知道您播放的数据不会离开您的应用,因此无需担心泄露私人数据。
其他应用程序无法将这些广播发送到您的应用,因此您无需担心他们可以利用安全漏洞。
它比通过系统发送全球广播更有效。
不在文档中:
Activity
,Application
,... <强>描述强>
因此,您要检查Activity
中是否有任何当前位于前台。您通常在Service
或Application
课程中执行该操作。
这意味着,您的Activity
个对象成为信号的发送者(我正在/我正在关闭)。另一方面,Service
成为Receiver
。
两个时刻,Activity
会告诉您它是在前台还是在后台(是的只有两个......不是6个)。
当Activity
进入前台时,会触发onResume()
方法(也会在onCreate()
之后调用)。
当Activity
进入后方时,会调用onPause()
。
这些是您Activity
应向您的Service
发送信号以描述其状态的时刻。
如果有多个Activity
,请记住,Activity
首先进入后台,然后另一个进入前景。
情况如下:*
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
Service
/ Application
只会继续听取这些信号并采取相应行动。
代码(TLDR)
您的Service
必须实施BroadcastReceiver
才能收听信号。
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")
在Receiver
Service::onCreate()
@Override
protected void onCreate() {
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
在Service::onDestroy()
@Override
protected void onDestroy() {
// I'm dead, no need to listen to anything anymore.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
现在你的Activity
必须传达他们的状态。
在Activity::onResume()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
在Activity::onPause()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
非常非常常见的情况
开发人员:我想从
Service
发送数据并更新Activity
。如何检查Activity
是否在前台?
通常无需检查Activity
是否在前台。只需通过您LocalBroadcastManager
的{{1}}发送数据即可。如果Service
已启用,则会响应并采取行动。
对于这种非常常见的情况,Activity
成为发件人,Service
实现Activity
。
因此,在BroadcastReceiver
中创建Receiver
。在Activity
中注册并在onResume()
中取消注册。 无需使用其他生命周期方法。
在onPause()
中定义Receiver
行为(更新ListView,执行此操作,执行此操作,...)。
这样onReceive()
只有在前景中才会收听,如果它在后面或被摧毁,则不会发生任何事情。
如果有多个Activity
,则Activity
处于启用状态将响应(如果它们也实现了Activity
)。
如果所有人都在后台,没有人会回应,信号就会迷失。
通过指定信号ID,从Receiver
通过Service
发送数据(请参阅上面的代码)。
答案 24 :(得分:0)
这个旧帖子的另一个解决方案(对于那些可能有帮助的帖子):
<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();
}
}
答案 25 :(得分:0)
B
答案 26 :(得分:0)
如果您想知道特定活动是否正在进行,以及您是否是无法直接访问该应用程序的SDK,则没有一个答案适合特定情况。对我来说,我处于后台线程中,刚刚收到了有关新聊天消息的推送通知,并且只想在聊天屏幕不在前台时显示系统通知。
使用其他答案中推荐的ActivityLifecycleCallbacks
,我创建了一个小型util类,其中包含MyActivity
是否在前景中的逻辑。
class MyActivityMonitor(context: Context) : Application.ActivityLifecycleCallbacks {
private var isMyActivityInForeground = false
init {
(context.applicationContext as Application).registerActivityLifecycleCallbacks(this)
}
fun isMyActivityForeground() = isMyActivityInForeground
override fun onActivityPaused(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = false
}
}
override fun onActivityResumed(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = true
}
}
}
答案 27 :(得分:0)
此代码将在任何情况下检查foreground
和background
:
Java代码:
private static boolean isApplicationForeground(Context context) {
KeyguardManager keyguardManager =
(KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardManager.isKeyguardLocked()) {
return false;
}
int myPid = Process.myPid();
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> list;
if ((list = activityManager.getRunningAppProcesses()) != null) {
for (ActivityManager.RunningAppProcessInfo aList : list) {
ActivityManager.RunningAppProcessInfo info;
if ((info = aList).pid == myPid) {
return info.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
}
}
}
return false;
}
科林代码:
private fun isApplicationForeground(context: Context): Boolean {
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (keyguardManager.isKeyguardLocked) {
return false
}
val myPid = Process.myPid()
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
var list: List<ActivityManager.RunningAppProcessInfo>
if (activityManager.runningAppProcesses.also { list = it } != null) {
for (aList in list) {
var info: ActivityManager.RunningAppProcessInfo
if (aList.also { info = it }.pid == myPid) {
return info.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
}
}
}
return false
}
答案 28 :(得分:0)
另一种没有额外依赖的方法是这个:
只需将此方法添加到您的应用程序类并在 onCreate() 中调用它
var isInBackground = true
private fun setupActivityLifecycleCallbacks() {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {
isInBackground = false
}
override fun onActivityPaused(activity: Activity) {
isInBackground = true
}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
})
}
AFAIK 你甚至可以将 isInBackground 设为静态,这样你就可以使用伴随对象在没有上下文的情况下访问它
答案 29 :(得分:0)
没有任何解决方案适合我,但我提出了一个原始解决方案。这应该有效。如果 isAppBackground 返回 false,则应用必须在前台。
public static boolean isAppBackground(Context context){
boolean isBackground=true;
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH){
List<ActivityManager.RunningAppProcessInfo> runningProcesses =activityManager.getRunningAppProcesses();
for(ActivityManager.RunningAppProcessInfo processInfo:runningProcesses){
if(processInfo.importance==ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
for(String activeProcess:processInfo.pkgList){
if(activeProcess.equals(context.getPackageName())){
isBackground = false;
}
}
}
}
}else{
List<ActivityManager.RunningTaskInfo> taskInfo = activityManager.getRunningTasks(1);
if(taskInfo.size()>0) {
ComponentName componentName = taskInfo.get(0).topActivity;
if(componentName.getPackageName().equals(context.getPackageName())){
isBackground = false;
}
}
}
return isBackground;
}
答案 30 :(得分:-1)
回答可能为时已晚,但如果有人来访,那么这是我建议的解决方案, 一个应用程序想要知道它处于后台或前景状态的原因可能很多,有些是, 1.当用户在BG时显示祝酒词和通知。 2.首次执行某些任务用户来自BG,如民意调查,重绘等。
Idolon和其他人的解决方案负责第一部分,但不是第二部分。如果您的应用中有多个活动,并且用户正在它们之间切换,那么当您处于第二个活动时,可见标记将为false。因此无法确定性地使用它。
我做了CommonsWare建议的事情,“如果服务确定没有可见的活动,并且它会保持一段时间,请在下一个逻辑中停止数据传输停止点。“
粗体线很重要,可用于实现第二项。所以我所做的是,一旦我得到onActivityPaused(),不要直接将visible更改为false,而是使用3秒的定时器(即下一个活动应该启动的最大值),如果没有onActivityResumed( )在接下来的3秒内调用,将可见变为false。 类似地,在onActivityResumed()中如果有一个计时器,那么我取消它。 总而言之,可见变为isAppInBackground。
抱歉无法复制粘贴代码......
答案 31 :(得分:-1)
在我的活动onResume和onPause中,我向SharedPrefences写了一个isVisible布尔值。
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
Editor editor = sharedPrefs.edit();
editor.putBoolean("visible", false);
editor.commit();
在需要时通过其他地方阅读
// 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)){...}
也许不优雅,但它对我有用......
答案 32 :(得分:-3)
我建议您使用其他方法来执行此操作。
我想你想在程序启动时显示启动屏幕,如果它已经在后端运行,请不要显示它。
您的应用程序可以连续将当前时间写入特定文件。 当您的应用程序启动时,请检查上一个时间戳,如果current_time-last_time&gt;您指定用于写入最新时间的时间范围,则表示您的应用程序已停止,系统或用户自己将其终止。