检测Android应用程序进入后台

9
我需要在我的应用“进入后台”或“不活动状态”时关闭蓝牙。
我尝试在MainActivity的onPause()中执行此操作,但这并不起作用,因为现在即使我启动一个新的活动显示选定项的实体细节,BT也会关闭(Mainactivity的onPause()被触发)。
我需要一种类似于我的应用程序的“onPause()”而不是单个活动的解决方案。
我认为没有类似的解决方案,那么有没有更好的解决方案?

兄弟,我已经遇到这个问题无数次了,但不幸的是没有这样的方法或事件存在...你必须找到一个解决办法。 - Abhishek Shukla
将以下程序相关内容从英语翻译成中文。仅返回翻译后的文本:将其放置在MainActivity的"onDestroy"和"onBackPressed"方法中,以便在用户关闭应用程序时关闭蓝牙。 - Abhishek V
onDestroy()不是我想要的,因为这个方法被调用可能需要一些时间。 - Petr B
7个回答

16
在您的 build.gradle 文件中引用此依赖项:
dependencies {
    implementation "android.arch.lifecycle:extensions:1.1.1"
}

然后在您的 Application 类中使用以下代码:

public class MyApplication extends Application implements LifecycleObserver {

    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private void onAppBackgrounded() {
        Log.d("MyApp", "App in background");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onAppForegrounded() {
        Log.d("MyApp", "App in foreground");
    }
}

更新你的AndroidManifest.xml文件:

<application
    android:name=".MyApplication"
    ....>
</application>

1
这是一个很棒的答案。非常感谢! - matdev
像魔法一样好用!顺便问一下,这是一个开源项目吗?或许在Github上?我想学习它的工作原理。 - kc ochibili

9

更新:请注意,根据评论,这种方法并不适用于所有情况!!!

我认为在stackoverflow网站上提供的解决方案过于复杂。我想出了以下解决方法:

创建静态变量,可从所有活动中访问,以检测当前正在运行的活动数量。

public class SharedData {
    static int runningActivities = 0;
}

在每个活动中重写这两种方法。

public void onStart() {
    super.onStart();
    if (SharedData.runningActivities == 0) {
        // app enters foreground
    }
    SharedData.runningActivities++;
}

public void onStop() {
    super.onStop();
    SharedData.runningActivities--;
    if (SharedData.runningActivities == 0) {
        // app goes to background
    }
}

您可以创建一个扩展Activity的MyActivity类,将以下代码放在其中,并使所有Activity继承此类。


1
这个不起作用,当活动被后退按钮恢复或从另一个活动进入时也会触发。 - CommonSenseCode
跟踪活动计数的一个陷阱是旋转。往往情况下,正在进行的活动在新配置的新活动出现之前就已经完全结束了,导致背景->前景转换检测不正确。 - bduhbya

3
要检测应用程序是否进入后台,请在您的应用程序的Application类中覆盖以下方法:
@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    if(level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN)
        //called when app goes to background
}

2
您可以参考这个问题:如何检测Android应用程序何时进入后台并回到前台,回答这个问题的人使用了onFocusChanged来解决,不知道这种方法有多有效,总之请继续在Google上研究。
private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(context.getPackageName())) {
            return true;
        }
    }

    return false;
}

至少到目前为止,它对我来说可以处理多个活动。 - Cristiano Santos

2

对于一个不是单一Activity的应用程序,我建议每个活动都实现基于时间的可见性控制。在每个onPause()方法中启动一个定时状态检查器,并在每个onResume()方法中取消此计时器。

以下是一个示例:

    @Override
protected void onPause() {
    TimerTask backgroundCheck = new TimerTask() {

        @Override
        public void run() {
            ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
            List<RunningTaskInfo> tasks = am.getRunningTasks(1);
            if (!tasks.isEmpty()) {
                ComponentName topActivity = tasks.get(0).topActivity;
                if (!topActivity.getPackageName().equals(getApplicationContext().getPackageName())) {
                    // APP in background, do something
                }
            }

            // APP in foreground, do something else
        }
    };

    Timer isBackgroundChecker = new Timer();
    isBackgroundChecker.schedule(backgroundCheck, 1000, 1000);

    super.onPause();
}

实施完毕后,记得取消 Timer isBackgroundChecker = new Timer();

请问您有这种方法的示例吗? - Petr B
getRunningTasks在API级别21(棒棒糖)中已被弃用。文档指出不要使用它,因为它可能会在未来出现“中断”。 - huync

2

1

您可以在每个活动中实现onPause(),但我认为没有必要自己关闭蓝牙,因为有些用户可能正在使用蓝牙进行其他操作,或者他们想自己关闭它(这就是我的做法)。


1
这样做不行,因为如果我离开主活动并打开我的应用程序中的另一个活动,那么BT将关闭。 - Petr B
你可以尝试使用片段(fragment)来解决问题。它们可以像活动(activity)一样运行,并且可以包含在单个活动中,在调用onPause()时关闭蓝牙。 - TomTsagk

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