所谓后台,我的意思是应用程序的活动目前对用户都不可见?
当前回答
如果你打开开发人员设置“不要保留活动”-只检查创建的活动数量不够。您还必须检查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) { }
}
其他回答
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
}
检测应用程序是否在后台运行的方法很少,但只有一种是完全可靠的:
The right solution (credits go to Dan, CommonsWare and NeTeInStEiN) Track visibility of your application by yourself using Activity.onPause, Activity.onResume methods. Store "visibility" status in some other class. Good choices are your own implementation of the Application or a Service (there are also a few variations of this solution if you'd like to check activity visibility from the service). Example Implement custom Application class (note the isActivityVisible() static method): 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; } Register your application class in AndroidManifest.xml: <application android:name="your.app.package.MyApplication" android:icon="@drawable/icon" android:label="@string/app_name" > Add onPause and onResume to every Activity in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended from MapActivity/ListActivity etc. you still need to write the following by hand): @Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); } Update ActivityLifecycleCallbacks were added in API level 14 (Android 4.0). You can use them to track whether an activity of your application is currently visible to the user. Check Cornstalks' answer below for the details. The wrong one I used to suggest the following solution: You can detect currently foreground/background application with ActivityManager.getRunningAppProcesses() which returns a list of RunningAppProcessInfo records. To determine if your application is on the foreground check RunningAppProcessInfo.importance field for equality to RunningAppProcessInfo.IMPORTANCE_FOREGROUND while RunningAppProcessInfo.processName is equal to your application package name. Also if you call ActivityManager.getRunningAppProcesses() from your application UI thread it will return importance IMPORTANCE_FOREGROUND for your task no matter whether it is actually in the foreground or not. Call it in the background thread (for example via AsyncTask) and it will return correct results. While this solution may work (and it indeed works most of the time) I strongly recommend to refrain from using it. And here's why. As Dianne Hackborn wrote: These APIs are not there for applications to base their UI flow on, but to do things like show the user the running apps, or a task manager, or such. Yes there is a list kept in memory for these things. However, it is off in another process, managed by threads running separately from yours, and not something you can count on (a) seeing in time to make the correct decision or (b) have a consistent picture by the time you return. Plus the decision about what the "next" activity to go to is always done at the point where the switch is to happen, and it is not until that exact point (where the activity state is briefly locked down to do the switch) that we actually know for sure what the next thing will be. And the implementation and global behavior here is not guaranteed to remain the same in the future. I wish I had read this before I posted an answer on the SO, but hopefully it's not too late to admit my error. Another wrong solution Droid-Fu library mentioned in one of the answers uses ActivityManager.getRunningTasks for its isApplicationBroughtToBackground method. See Dianne's comment above and don't use that method either.
不要用这个答案
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()。
这篇旧文章的另一个解决方案(对那些可能有帮助的人来说):
<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();
}
}
在我的onResume和onPause活动中,我写了一个isVisible布尔值给sharedpreferences。
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)){...}
也许不优雅,但对我来说很管用……
推荐文章
- 警告: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文件