Answers:
有几种方法可以检测您的应用程序是否在后台运行,但是只有其中一种是完全可靠的:
正确的解决方案(学分去丹,CommonsWare和NeTeInStEiN)
使用自己的应用程序的轨道知名度Activity.onPause
,Activity.onResume
方法。将“可见性”状态存储在其他一些类中。好的选择是您自己实现Application
或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;
}
在以下位置注册您的应用程序类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();
}
更新
ActivityLifecycleCallbacks已在API级别14(Android 4.0)中添加。您可以使用它们来跟踪用户当前是否可以看到应用程序的活动。有关详细信息,请查看下面的 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的评论,也不要使用该方法。
OnStop
应要求isActivityVisible
。
user1269737的答案是执行此操作的正确方法(已获得Google / 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;
}
*/
}
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()方法后保持活动的进程运行),该方法永远不会被调用。
这里的关键是“让您的活动的进程保持运行 ……”如果达到这种内存不足的情况,您的进程实际上将被杀死(而不仅仅是活动)。这意味着这种检查背景色的方法仍然有效,因为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()
。
onStop()
after中检查背景super.onStop()
。不要检查中的背景onPause()
。
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
}
}
在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' }
}
}
您可以在此处阅读有关Lifecycle相关架构组件的更多信息-https: //developer.android.com/topic/libraries/architecture/lifecycle
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }
可以更轻松地访问前景/背景状态:然后您可以使用ArchLifecycleApp.isForeground()
The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes.
,这不适用于multiple processes
应用程序,我们可以优雅地实现一些api吗?
从支持库版本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
}
然后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);
从Android API 16开始,有一种简单的方法可以检查应用程序是否在前台。它可能不是万无一失的,但是Android上没有任何方法是万无一失的。当您的服务从服务器接收更新并且必须决定是否显示通知时,此方法足够好使用(因为如果UI是前台,用户将在没有通知的情况下注意到更新)。
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
JobService
来检测该服务在后台运行。
Idolon的答案容易出错,并且更复杂,尽管在这里重复检查Android应用程序是否在前台?在这里从后台任务或服务确定当前的前台应用程序
有一种更简单的方法:
在所有活动都扩展的BaseActivity上:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
每当您需要检查是否有任何应用程序活动处于前台时,只需检查一下即可 isVisible()
;
要了解这种方法,请检查并排活动生命周期的以下答案:活动并排生命周期
Idolon's answer is error prone
-很遗憾,我必须同意你的看法。根据Dianne Hackborn在Google网上论坛中的评论,我更新了答案。请检查以获取详细信息。
我尝试了使用Application.ActivityLifecycleCallbacks和其他许多应用程序的推荐解决方案,但是它们没有按预期工作。感谢Sarge,我想出了一个非常简单明了的解决方案,下面将对此进行介绍。
解决方案的关键是要了解以下事实:如果我们有ActivityA和ActivityB,并从ActivityA调用ActivityB(而不是调用
ActivityA.finish
),那么onStart()
将在 ActivityA 之前调用ActivityBonStop()
。
这也是主要的区别onStop()
,并onPause()
认为没有在我读的文章只是提及。
因此,根据此活动的生命周期行为,您可以简单地算出执行了多少次onStart()
,onPause()
得到了程序中调用的。请注意,对于每个 Activity
程序,您都必须覆盖onStart()
和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--;
}
}
现在我们的程序的每个活动,我们应该重写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()
。
if(Utilities.isApplicationOnBackground()) …
到Utilities
。因为否则,只有特定活动会对事件做出反应。
除非您自己进行跟踪,否则无法确定您的任何活动是否可见。也许您应该考虑提出一个新的StackOverflow问题,以说明您要从用户体验中实现的目标,因此我们也许可以为您提供替代的实现思路。
Service
。如果是这样,请让您的活动在服务出现或消失时通知服务。如果Service
确定没有可见的活动,并且仍然保持这种状态一段时间,请在下一个逻辑停止点停止数据传输。是的,这将需要您每个活动的代码,但是现在,这是不可避免的AFAIK。
MyActivityClass
继承Activity
并实现生命周期方法的类,并使所有活动都继承自MyActivityClass
。这会为没有工作PreferenceActivity
或MapActivity
虽然(见这个问题)
您可以使用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
}
}
}
在@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;
}
}
我想出的最好的解决方案是使用计时器。
您已经在onPause()中启动了一个计时器,并在onResume()中取消了同一计时器,该计时器有1个实例(通常在Application类中定义)。计时器本身设置为在2秒钟后(或您认为合适的任何间隔)运行一次Runnable,当计时器触发时,您将标志设置为将应用程序标记为处于后台。
在取消计时器之前,可以在onResume()方法中查询后台标志以执行任何启动操作(例如,开始下载或启用定位服务)。
此解决方案使您可以在后台进行多个活动,并且不需要任何许可即可实现。
如果您也使用事件总线,则此解决方案效果很好,因为您的计时器可以简单地触发事件,并且应用的各个部分都可以相应地做出响应。
如果您打开开发人员设置“不保留活动”-仅检查创建的活动数是不够的。您还必须检查isSaveInstanceState。我的自定义方法isApplicationRunning()检查android应用是否正在运行:
这是我的工作代码:
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) { }
}
唯一正确的解决方案:
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) {
...
}
}
}
为了了解CommonsWare和Key所说的内容,您可以扩展Application类,并让所有活动在其onPause / onResume方法上进行调用。这将使您知道哪些活动是可见的,但是可能可以更好地进行处理。
您能否详细说明您的想法?当您说在后台运行时,您的意思是即使您的应用程序当前不在屏幕上,也只是将其保留在内存中?您是否考虑过将服务作为一种更持久的方式来管理您的应用程序(当应用程序没有重点关注时)?
Application
没有onPause()
或onResume()
。
我做了自己的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实现中编程的日志。
由于尚未提及,因此我建议读者探索可通过Android Architecture组件获得的ProcessLifecycleOwner
该系统区分前台和后台应用程序。(背景的服务限制目的的定义是从由存储器管理中使用的定义不同的;一个应用程序可能是在后台涉及存储器管理,但在前景作为涉及它能够发射服务)。一个应用程序是如果满足以下任一条件,则视为处于前台:
如果所有这些条件都不成立,则认为该应用程序处于后台。
此旧帖子的另一种解决方案(适用于那些可能有帮助的帖子):
<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();
}
}
请参阅onActivityDestroyed函数中的注释。
适用于SDK目标版本14>:
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
public static int active = 0;
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
active--;
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
active++;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
active++;
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
active--;
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
active--;
// if active var here ever becomes zero, the app is closed or in background
if(active == 0){
...
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
active++;
}
}
我认为这个问题应该更清楚。什么时候?哪里?如果您的应用程序在后台运行,您想知道什么具体情况?
我只是以自己的方式介绍我的解决方案。
我通过在我的应用程序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;
}
我建议通读此页: http //developer.android.com/reference/android/app/Activity.html
简而言之,onStop()
调用之后,您的活动将不再可见。
onStop
; 在它之间onPause
,onStop
并且可见,但在前景中不可见。
onStop()
调用后不再可见,这与您编写的内容一致。
onPause
是直到被调用:最近的修改已纠正您。
在我看来,许多答案会带来大量代码负担,并带来许多复杂性和不可读取性。
当人们问SO Service
和a 之间如何通信时Activity
,我通常建议使用LocalBroadcastManager。
为什么?
好吧,通过引用文档:
您知道您正在广播的数据不会离开您的应用程序,因此无需担心泄漏私人数据。
其他应用程序不可能将这些广播发送到您的应用程序,因此您无需担心会利用它们的安全漏洞。
它比通过系统发送全局广播更有效。
不在文档中:
Activity
,Application
...描述
因此,您想检查Activity
当前是否有任何前台。您通常在Service
或您的Application
班级中这样做。
这意味着,您的Activity
对象成为信号的发送者(我打开/我关闭)。你Service
,在另一方面,变成Receiver
。
有两个时刻,您的Activity
告诉您它是在前台还是在后台(是,只有两个,而不是6)。
当Activity
进入前台时,将onResume()
触发该方法(也称为after 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
从你的Service
。如果Activity
打开,则它将响应并采取行动。
对于这种非常常见的情况,Service
成为发送者,并Activity
实现BroadcastReceiver
。
因此,创建一个Receiver
在你的Activity
。在中注册,然后在中onResume()
注销onPause()
。无需使用其他生命周期方法。
Receiver
在onReceive()
(更新ListView,执行此操作,执行此操作,...)中定义行为。
这样,Activity
仅当它在前景中时,它才会侦听,而如果它在后方或被破坏,则什么也不会发生。
如果有多个Activity
,则无论哪个Activity
启用(如果它们也实现Receiver
)都会响应。
如果全部都在后台,则没人会响应,信号只会丢失。
通过指定信号ID 从Service
通孔发送数据Intent
(请参见上面的代码)。
fun isAppInForeground(): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager ?: return false
val appProcesses = activityManager.runningAppProcesses ?: return false
val packageName = packageName
for (appProcess in appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName) {
return true
}
}
return false
}
如果您想了解特定活动是否在前景中,以及您是否是无法直接访问该应用程序的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
}
}
}
在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)){...}
也许不优雅,但是对我有用。
回答可能为时已晚,但是如果有人来访问,那么这就是我建议的解决方案,一个应用想要知道其处于后台或进入前台状态的原因可能很多,其中一些是1。当用户在BG中时显示敬酒和通知。2.要首次执行某些任务的用户来自BG,例如投票,重绘等。
Idolon和其他人的解决方案只涉及第一部分,而不适用于第二部分。如果您的应用中有多个活动,并且用户正在它们之间进行切换,那么当您进入第二个活动时,可见标志将为false。因此,不能确定地使用它。
我做了CommonsWare所建议的操作,“如果服务确定没有可见的活动,并且这种方式保持了一段时间,请在下一个逻辑停止点停止数据传输。”
粗线非常重要,可用于实现第二项。因此,我要做的就是一旦获得onActivityPaused(),不要直接将visible更改为false,而是要设置3秒的计时器(这是应该启动下一个活动的最大值),如果没有onActivityResumed( )在接下来的3秒钟内致电,将可见更改为false。同样,如果有计时器,则在onActivityResumed()中取消它。综上所述,可见变为isAppInBackground。
抱歉,无法复制粘贴代码...