所谓后台,我的意思是应用程序的活动目前对用户都不可见?
当前回答
我尝试了推荐的使用Application的解决方案。ActivityLifecycleCallbacks和许多其他的,但是它们没有像预期的那样工作。感谢Sarge,我想出了一个非常简单和直接的解决方案,我将在下面描述。
解决方案的关键是理解这样一个事实:如果我们有ActivityA和ActivityB,并且我们从ActivityA调用ActivityB(而不是调用ActivityA.finish),那么ActivityB的onStart()将在ActivityA onStop()之前被调用。
这也是onStop()和onPause()之间的主要区别,在我读过的文章中没有人提到。
So based on this Activity's Lifecycle behavior, you can simply count how many times did onStart() and onPause() got called in your program. Note that for each Activity of your program, you must override onStart() and onStop(), in order to increment/decrement the static variable used for counting. Below is the code implementing this logic. Note that I am using a class that extends Application, so dont forget to declare on Manifest.xml inside Application tag: android:name=".Utilities", although it can be implemented using a simple custom class too.
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()中检查你的应用程序是否在后台。
其他回答
如果你打开开发人员设置“不要保留活动”-只检查创建的活动数量不够。您还必须检查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) { }
}
我尝试了推荐的使用Application的解决方案。ActivityLifecycleCallbacks和许多其他的,但是它们没有像预期的那样工作。感谢Sarge,我想出了一个非常简单和直接的解决方案,我将在下面描述。
解决方案的关键是理解这样一个事实:如果我们有ActivityA和ActivityB,并且我们从ActivityA调用ActivityB(而不是调用ActivityA.finish),那么ActivityB的onStart()将在ActivityA onStop()之前被调用。
这也是onStop()和onPause()之间的主要区别,在我读过的文章中没有人提到。
So based on this Activity's Lifecycle behavior, you can simply count how many times did onStart() and onPause() got called in your program. Note that for each Activity of your program, you must override onStart() and onStop(), in order to increment/decrement the static variable used for counting. Below is the code implementing this logic. Note that I am using a class that extends Application, so dont forget to declare on Manifest.xml inside Application tag: android:name=".Utilities", although it can be implemented using a simple custom class too.
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()中检查你的应用程序是否在后台。
您应该使用共享首选项来存储属性,并使用来自活动的服务绑定对其进行操作。如果你只使用绑定(也就是从不使用startService),那么你的服务将只在你绑定它时运行,(绑定onResume和取消绑定onPause),这将使它只在前台运行,如果你确实想在后台工作,你可以使用常规的启动停止服务。
检测应用程序是否在后台运行的方法很少,但只有一种是完全可靠的:
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.
参见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++;
}
}
推荐文章
- 警告: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文件