检查Android应用程序是否在后台运行

376

所谓背景,指的是应用程序的所有活动当前对用户都不可见。


3
可能是重复的问题:如何确定我的活动是否在前台。 - Phrogz
12
我有点困惑……为什么安卓不能在应用程序类中简单地提供一个覆盖方法来处理这个问题呢?难道在平台层面上无法解决吗?@Override protected void onApplicationSentToBackground() { } - Chuck D
2
@ChuckD - 这是有道理的,这也是Android SDK有时候喜欢避免做的事情。 :/ - Mark
http://codingaffairs.blogspot.com/2016/05/check-if-your-android-app-is-in.html - Developine
2
iOS在这方面做得非常好,不确定为什么谷歌让这变得如此困难。这是一个非常明显的需求。 - Jerry Destremps
显示剩余5条评论
37个回答

3
如果你打开了开发者选项中的“不保留活动”,仅检查已创建的活动数是不够的。你还需要检查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) { }        

}

3
我想到的最好的解决方案是使用计时器。
在onPause()中启动一个计时器,在onResume()中取消同一个计时器,有1个计时器实例(通常在Application类中定义)。计时器本身设置为在2秒后(或您认为适当的任何间隔)运行一个Runnable,当计时器触发时,您将标记应用程序为处于后台状态。
在取消计时器之前的onResume()方法中,您可以查询后台标志以执行任何启动操作(例如启动下载或启用位置服务)。
这个解决方案允许您在后台堆栈上拥有几个活动,并且不需要任何权限来实现。
如果您还使用事件总线,则此解决方案也很有效,因为您的计时器可以简单地触发一个事件,您的应用程序的各个部分可以相应地响应。

我开始认为这是最好的(尽管不幸的)解决方案。 - dhaag23
是的,这是我找到的最佳解决方案。当应用程序不在前台时,我需要停止蓝牙扫描,但不能仅使用onPause、stop或destroy,因为我不想在用户浏览应用程序时不断停止和启动。 - CaptRespect

2

唯一正确的解决方案:

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        MyApp.mainActivity = this;
        super.onCreate(savedInstanceState);
        ...
    }

MyApp.java:

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) {
            ...
        }
    }

}

我不明白这个解决方案如何在我的活动(或片段)中的IF语句中给我一个简单问题的答案,无论我的应用程序是在后台还是前台。 "IF"语句在哪里??? - ekashking

2

没有任何解决方案适用于我,但是我提出了一个简单的解决方案。这应该可以解决问题。如果 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;
    }

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中实现的接口中编程的日志记录。

2

为了顺应CommonsWare和Key所说的,您可以扩展Application类,并让所有活动在其onPause/onResume方法中调用它。这将使您能够知道哪个Activity(ies)可见,但这可能可以更好地处理。

您能详细说明您的想法吗?当您说在后台运行时,您是否意味着即使当前不在屏幕上,您的应用程序仍然在内存中?您是否考虑过使用服务作为一种更持久的方式来管理您的应用程序,当它没有焦点时?


在 Android 中,我们有一个名为“后台数据”的设置。当应用程序在后台运行时,此设置会关闭任何后台数据连接。我想为我的应用程序实现“后台数据”开关,这样当用户看不到我的任何活动时,我希望停止进行任何数据传输,但是一旦我的一个活动恢复,我就希望恢复数据传输。 - cppdev
1
应用程序没有 onPause()onResume() - CommonsWare
1
@CommonsWare 您是正确的,我指的是每个单独的Activity在暂停/恢复时联系应用程序。这基本上是您在回答评论中分享的想法,尽管您使用了Services,我想这是一个更明智的选择。 - Dan

2

官方文档:

系统区分前台应用和后台应用。 (与内存管理所使用的定义不同,服务限制中背景的定义是特指后台应用;一个应用可能对于内存管理来说处于后台状态,但对于其启动服务的能力来说却处于前台状态。) 如果以下任意一项为真,则视应用为在前台运行:

  1. 它有一个可见的活动,无论该活动是已启动还是已暂停。
  2. 它有一个前台服务。
  3. 另一个前台应用连接到该应用,不管是通过绑定到其中一个其服务或是利用其中一个内容提供者。例如,如果另一个应用程序绑定到该应用的:
    • 输入法编辑器
    • 壁纸服务
    • 通知监听器
    • 语音或文本服务

如果以上条件都不成立,则应用被视为在后台运行。


1

简单明了的回答:

override fun onPause() {
    Log.i("APP LIFECYCLE", "App Enter BACKground")
    isForeground = false
    super.onPause()
}

override fun onResume() {
    Log.i("APP LIFECYCLE", "App Enter FOREground")
    isForeground = true
    super.onResume()
}

那么只需使用您的活动的 isForeground 属性来检查状态即可。

1

3
我应用程序中大约有10个活动,所以我想知道它们是否对用户可见。总之,我想知道我的应用程序整体是否在后台运行。 - cppdev
那么你就要跟踪所有的10个左右。或者,正如CommonsWare建议的那样,解释一下你想要做什么。 - Key
3
这不正确。您的Activity在 onStop 之前是可见的;在 onPauseonStop 之间,它仍然是可见的,但不是在前台 - nickgrim
@nickgrim:什么不正确?我说过,在调用onStop()后,活动将不再可见,这与您所写的相符。 - Key
@关键字:您最初说直到“onPause”被调用:最近的编辑已经更正了您的说法。 - nickgrim

1
当弹窗出现时,活动会暂停,因此所有推荐的解决方案都是不完整的解决方案。您需要为对话框创建钩子。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接