检查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个回答

0

请查看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++;
    }
}

0

没有一个答案完全适合特定情况,如果您想知道特定活动是否在前台,并且如果您是没有直接访问应用程序的SDK。对于我来说,我在后台线程中刚刚收到了新聊天消息的推送通知,并且只想在聊天屏幕不在前台时显示系统通知。

使用其他答案中推荐的ActivityLifecycleCallbacks,我创建了一个小型实用程序类,其中包含逻辑以确定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
    }
}

}


0

这个在2023年仍然有效

1-请进入您的应用程序类。 (如果您没有任何应用程序类,则请添加一个扩展Application的类)

2-然后在您的应用程序类中添加私有静态变量以存储状态。

3-然后在您的应用程序中实现LifecycleEventObserver及其单个方法“onStateChanged”

4-最后,在您的应用程序中添加静态方法,以从任何活动或片段中获取私有变量的状态

public class MyApp extends Application implements LifecycleEventObserver{

    private static boolean activityVisible;

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event)
    {
        if (event == Lifecycle.Event.ON_STOP) {
            activityVisible = false;
        }
        else if (event == Lifecycle.Event.ON_PAUSE){
            activityVisible = false;
        }
        else if (event == Lifecycle.Event.ON_RESUME){
            activityVisible = true;
        }
        else if (event == Lifecycle.Event.ON_START) {
            activityVisible = true;
        }
    }

    public static boolean checkIfActivityVisible(){
        return activityVisible;
    }

}

0

这里有多种方法

  1. 使用LifecycleEventObserver。在此处,ProcessLifecycleOwner为整个应用程序进程提供生命周期。因此,在应用程序进入前台/后台时调用onStateChanged,而在Activity切换之间不会调用。
import android.app.Application
import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner

class TestApplication: Application(), LifecycleEventObserver {

    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this);
    }

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        Log.i("AppForegrounded", "Hello event ${event}")
        if (event == Lifecycle.Event.ON_RESUME) {
            isAppInForeground = true
        } else {
            isAppInForeground = false
        }
    }

    companion object {
        var isAppInForeground = false
    }
}

然后在Activity中将其用作

TestApplication.isAppInForeground

请确保在清单文件中提及此应用程序类

<manifest>
    <application
           android:name=".app.TestApplication"
    </application>
</manifest>

我们还可以将isAppInForeground字段设置为可观察的,这样我们就可以监听变化而不是在进行某些操作之前检查应用是否在前台。
2. 使用DefaultLifecycleObserver。在这里,ProcessLifecycleOwner为整个应用程序进程提供生命周期。因此,当应用程序进入前台/后台时,onResume或onPause被调用,而在Activity切换之间不会调用。
class TestApplication: Application(), DefaultLifecycleObserver {

    override fun onCreate() {
        super<Application>.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this);
    }

    override fun onResume(owner: LifecycleOwner) {
        super.onResume(owner)
        isAppInForeground = true
    }

    override fun onPause(owner: LifecycleOwner) {
        super.onPause(owner)
        isAppInForeground = false
    }

    companion object {
        var isAppInForeground = false
    }
}
  • 使用ProcessLifecycleOwner的currentState字段
  • val isAppInForeground = ProcessLifecycleOwner.get().lifecycle.currentState == Lifecycle.State.RESUMED
    val isAppInBackground = ProcessLifecycleOwner.get().lifecycle.currentState == Lifecycle.State.CREATED
    
    

    -1

    可能已经晚了,但如果有人来访问,这是我建议的解决方案, 应用程序想要知道它处于后台或前台状态的原因可能有很多,其中一些是, 1. 当用户在BG中时显示烤面包和通知。 2.第一次用户从BG进入时执行某些任务,例如投票,重绘等。

    Idolon和其他人提出的解决方案解决了第一部分,但没有解决第二部分。如果您的应用程序中有多个活动,并且用户在它们之间切换,则到您进入第二个活动时,可见标志将为false。因此,无法确定地使用它。

    我做了一些CommonsWare建议的事情,“如果服务确定没有可见的活动,并且保持这种状态一段时间,在下一个逻辑停止点停止数据传输。”

    加粗的那一行非常重要,可以用来实现第二个项目。所以我在获得onActivityPaused()时,不直接将可见性更改为false,而是设置一个3秒的计时器(这是下一个活动应该启动的最大时间),如果在接下来的3秒钟内没有onActivityResumed()调用,则更改可见性为false。

    同样,在onActivityResumed()中,如果有计时器,则会取消计时器。总之,visible变成了isAppInBackground。

    抱歉无法复制粘贴代码...


    -2
    在我的onResume和onPause活动中,我将一个isVisible布尔值写入SharedPrefences。
        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)){...}
    

    可能不太优雅,但对我来说很好用...


    -3

    我想建议您使用另一种方法来实现这个。

    我猜您想在程序启动时显示启动屏幕,如果它已经在后台运行,则不要显示它。

    您的应用程序可以持续将当前时间写入特定文件。当您的应用程序启动时,请检查最后一个时间戳,如果current_time-last_time>您指定的最新时间的时间范围,则意味着您的应用程序已停止,可能被系统或用户本身杀死。


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