所谓后台,我的意思是应用程序的活动目前对用户都不可见?
当前回答
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
}
其他回答
由于没有提到它,我将建议读者探索通过Android架构组件提供的ProcessLifecycleOwner
我建议你仔细阅读这个页面:http://developer.android.com/reference/android/app/Activity.html
简而言之,你的活动在onStop()被调用后不再可见。
不要用这个答案
user1269737的答案是正确的(谷歌/Android批准)方法来做到这一点。去读他们的答案,给他们一个+1。
为了子孙后代,我将把我最初的答案留在这里。这在2012年是最好的,但现在Android已经对此提供了适当的支持。
原来的答案
The key is using ActivityLifecycleCallbacks (note that this requires Android API level 14 (Android 4.0)). Just check if the number of stopped activities is equal to the number of started activities. If they're equal, your application is being backgrounded. If there are more started activities, your application is still visible. If there are more resumed than paused activities, your application is not only visible, but it's also in the foreground. There are 3 main states that your activity can be in, then: visible and in the foreground, visible but not in the foreground, and not visible and not in the foreground (i.e. in the background).
这个方法的真正优点是它没有getRunningTasks()所做的异步问题,但你也不必修改应用程序中的每个Activity来设置/取消onresume ()/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。
这是否适用于配置更改?
By default, no. You have to explicitly set configChanges=orientation|screensize (| with anything else you want) in your manifest file and handle the configuration changes, or else your activity will be destroyed and recreated. If you do not set this, your activity's methods will be called in this order: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume. As you can see, there is no overlap (normally, two activities overlap very briefly when switching between the two, which is how this backgrounding-detection method works). In order to get around this, you must set configChanges so that your activity is not destroyed. Fortunately, I've had to set configChanges already in all of my projects because it was undesirable for my entire activity to get destroyed on screen rotate/resize, so I've never found this to be problematic. (thanks to dpimka for refreshing my memory on this and correcting me!)
注意:一个
当我在这个回答中说“背景”时,我的意思是“你的应用不再可见”。Android活动可以是可见的,但不是在前台(例如,如果有一个透明的通知覆盖)。这就是为什么我更新了这个答案来反映这一点。
重要的是要知道,当切换活动时,前台没有任何东西,Android有一个奇怪的边缘时刻。出于这个原因,如果你在切换活动(在同一个应用程序中)时检查你的应用程序是否在前台,你会被告知你不在前台(即使你的应用程序仍然是活动的应用程序并且可见)。
你可以在super.onPause()之后的Activity的onPause()方法中检查你的应用程序是否在前台。记住我刚才说过的奇怪的边缘状态。
你可以检查你的应用程序是否可见(即如果它不在后台)在你的活动的onStop()方法后super.onStop()。
我想出的最好的解决办法是使用计时器。
你已经在onPause()中启动了一个定时器,并在onResume()中取消了相同的定时器,有一个定时器的实例(通常在应用程序类中定义)。计时器本身被设置为在2秒后(或您认为合适的任何时间间隔)运行Runnable,当计时器触发时,您设置一个标志,将应用程序标记为在后台。
在取消定时器之前的onResume()方法中,您可以查询后台标志来执行任何启动操作(例如开始下载或启用位置服务)。
这个解决方案允许您在back堆栈上有几个活动,并且不需要任何权限来实现。
如果你也使用事件总线,这个解决方案也很有效,因为你的计时器可以简单地触发一个事件,应用程序的各个部分可以相应地做出响应。
如果你想知道一个特定的活动是否在前台,如果你是一个没有直接访问应用程序的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
}
}
}
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 碎片中的onCreateOptionsMenu
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- DSL元素android.dataBinding。enabled'已过时,已被'android.buildFeatures.dataBinding'取代
- ConstraintLayout:以编程方式更改约束
- PANIC: AVD系统路径损坏。检查ANDROID_SDK_ROOT值
- 如何生成字符串类型的buildConfigField
- Recyclerview不调用onCreateViewHolder
- Android API 21工具栏填充
- Android L中不支持操作栏导航模式
- 如何在TextView中添加一个子弹符号?
- PreferenceManager getDefaultSharedPreferences在Android Q中已弃用
- 在Android Studio中创建aar文件