Android如何检查应用程序是否已关闭?

6

我有一个安卓应用程序,我需要一个函数或者任何广播接收器,可以检查这个应用程序是否被关闭。我不需要在每个活动中调用on destroy(该应用程序中有大约20个活动)我试图在Application类中添加这个函数。

public class ApplicationLifeCycleManager implements ActivityLifecycleCallbacks {

/** Manages the state of opened vs closed activities, should be 0 or 1.
 * It will be 2 if this value is checked between activity B onStart() and
 * activity A onStop().
 * It could be greater if the top activities are not fullscreen or have
 * transparent backgrounds.
 */
private static int visibleActivityCount = 0;

/** Manages the state of opened vs closed activities, should be 0 or 1
 * because only one can be in foreground at a time. It will be 2 if this
 * value is checked between activity B onResume() and activity A onPause().
 */
private static int foregroundActivityCount = 0;

/** Returns true if app has foreground */
public static boolean isAppInForeground(){
    return foregroundActivityCount > 0;
}

/** Returns true if any activity of app is visible (or device is sleep when
 * an activity was visible) */
public static boolean isAppVisible(){
    return visibleActivityCount > 0;
}

public void onActivityCreated(Activity activity, Bundle bundle) {
}

public void onActivityDestroyed(Activity activity) {
    Log.wtf("destroyed","app closed!!");
}

public void onActivityResumed(Activity activity) {
    foregroundActivityCount ++;
}

public void onActivityPaused(Activity activity) {
    foregroundActivityCount --;
}

public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}

public void onActivityStarted(Activity activity) {
    visibleActivityCount ++;
}

public void onActivityStopped(Activity activity) {
    visibleActivityCount --;
}
}

我还在应用程序类中注册了onCreate。

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new ApplicationLifeCycleManager());
}

但是在我切换活动时,onPaused、onResumed和onDestroyed函数会被调用:因为它检测任何活动是否关闭、销毁甚至恢复。

那么有没有一种解决方案可以在一个函数中检查应用程序是否关闭?


请尝试访问此链接:http://stackoverflow.com/q/33818406/7320259 - Zaki Pathan
1
你想要检查应用程序是在前台还是后台吗? - CoderP
我想要一个监听器,当用户通过按下返回或主页按钮关闭应用程序时,能够接收到一些信息。 - Amalo
2
ProcessLifecycleOwner是最新的解决方案。 - S.R
6个回答

14

这个答案使用了 ProcessLifecycleOwner 来检测应用程序的可见性。

这是 Android Architecture Component 的一部分。


1. 将此库添加到您的项目中:

implementation "android.arch.lifecycle:extensions:1.1.1"

2. 扩展实现 LifecycleObserver 的应用程序类

public class AppController extends Application implements LifecycleObserver {


///////////////////////////////////////////////
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onEnterForeground() {
        Log.d("AppController", "Foreground");
        isAppInBackground(false);
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onEnterBackground() {
        Log.d("AppController", "Background");
        isAppInBackground(true);
    }
///////////////////////////////////////////////



    // Adding some callbacks for test and log
    public interface ValueChangeListener {
        void onChanged(Boolean value);
    }
    private ValueChangeListener visibilityChangeListener;
    public void setOnVisibilityChangeListener(ValueChangeListener listener) {
        this.visibilityChangeListener = listener;
    }
    private void isAppInBackground(Boolean isBackground) {
        if (null != visibilityChangeListener) {
            visibilityChangeListener.onChanged(isBackground);
        }
    }
    private static AppController mInstance;
    public static AppController getInstance() {
        return mInstance;
    }

   
   
    @Override
    public void onCreate() {
        super.onCreate();

        mInstance = this;

        // addObserver
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
    }

}

并像这样使用:

AppController.getInstance().setOnVisibilityChangeListener(new ValueChangeListener() {
    @Override
    public void onChanged(Boolean value) {
        Log.d("isAppInBackground", String.valueOf(value));
    }
});

不要忘记将应用程序的名称添加到您的清单文件中。

<application
    android:name="myPackageName.AppController"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"">

完成。


(Kotlin示例)

https://github.com/jshvarts/AppLifecycleDemo


嗨S.R.如何将应用程序带回前台?因此,每当按下“最近使用的应用”和“主页”按钮时,它始终在前台。 - frozenade

6
您可以使用此函数来确定应用程序是否已关闭(既不在后台也不在前台)。
private boolean isAppRunning() {
    ActivityManager m = (ActivityManager) this.getSystemService( ACTIVITY_SERVICE );
    List<ActivityManager.RunningTaskInfo> runningTaskInfoList =  m.getRunningTasks(10);
    Iterator<ActivityManager.RunningTaskInfo> itr = runningTaskInfoList.iterator();
    int n=0;
    while(itr.hasNext()){
        n++;
        itr.next();
    }
    if(n==1){ // App is killed
        return false;
    }

    return true; // App is in background or foreground
}

您可以使用此函数检查应用程序是否在前台运行: https://dev59.com/Hmoy5IYBdhLWcg3wiegp#8490088

这个会在几分钟后被调用,否则本来就完美了 :( - Pooja Singh

4

使用从Application类开始的一个服务。

public class AppService extends Service {

    @Override
    public void onTaskRemoved(Intent rootIntent) {

        super.onTaskRemoved(rootIntent);
        //here you will get call when app close.
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

从应用程序类启动此服务。

@Override
public void onCreate() {
    super.onCreate();
    Intent intent = new Intent(getApplicationContext(), AppService.class);
    startService(intent);
}

2
只有在最近使用的应用程序中清除该应用程序时,它才能正常工作。 - OhhhThatVarun
onTaskRemoved()根本没有被调用。 - Pooja Singh

2
基本上,根据您的问题,您想要跟踪应用程序中的状态更改。
考虑到所有用例,这可能很难做到。但是有一个非常棒的库RxAppState可以很好地解决这个问题,而且使用起来非常简单。
我已经使用了这个库相当长的一段时间,它在所有情况下都运行良好。我强烈建议您尝试一下。

3
已弃用......ProcessLifecycleOwnerAndroid Architecture Component的一部分,是首选。演示如何使用ProcessLifecycleOwner的Kotlin示例项目在此处 - S.R

1

和 @S.R 的回答类似,您也可以在自定义应用程序中使用接口“Application.ActivityLifecycleCallbacks”,然后在“onActivityStopped”中使用“isAppOnForeground(Context)”方法。

public class MyApplication extends Application import Application.ActivityLifecycleCallbacks{

[ Code of ur app class...]

/* START Override ActivityLifecycleCallbacks Methods */
    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {
        mActivitiesBackStack.add(activity.getClass());
    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {
        if(!AppUtils.isAppOnForeground(this)){
            [Code when app in background...]
        }
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        if(mActivitiesBackStack.contains(activity.getClass())){
            mActivitiesBackStack.remove(activity.getClass());
        }
    }
    /* END Override ActivityLifecycleCallbacks Methods */

[ Code of ur app class...]

每当应用程序进入后台时调用此函数,而不是在关闭时调用。 如果将“isAppOnForeground”放在“onActivityDestroyed”中,则无法与上面的“isAppOnForeground”代码一起使用,因为它找不到进程(我想),也许更改上面的代码或使用另一种实现方式就可以了。 当应用程序关闭时,“onActivityDestroyed”将被调用,因此如果您可以在调用它时检查应用程序是否在后台(因此应用程序已经关闭),则可以准确地获取应用程序关闭的时刻。

“isAppOnForeground”的代码(我在一个Utils静态类中使用它):

public static boolean isAppOnForeground(Context context) {
        boolean ret = false;
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        if(appProcesses != null){
            String packageName = context.getPackageName();
            for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
                if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
                    ret = true;
                }
            }
        }
        return ret;
    }

希望这对你有所帮助,再见并愉快地编程!:D

使用这段代码,您将在应用程序进入后台时获得通知,而不仅仅是在应用程序关闭时。 我建议在应用程序进入后台时释放所有组件,然后在应用程序返回前台时重新分配它们。 - Z3R0

0
public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        if (isAppForground(context)) {
            // App is in Foreground
        } else {
            // App is in Background
        }
    }

     private boolean isAppOnForeground(Context context,String appPackageName) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        if (appProcesses == null) {
             //App is closed
            return false;
        }
        final String packageName = appPackageName;
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
     //                Log.e("app",appPackageName);
                return true;
            }else{
                //App is closed
            }
        }
        return false;
    }

}  

也添加这个权限

<uses-permission android:name="android.permission.GET_TASKS" />

试试这个,希望能有所帮助。


这个函数必须每隔1秒被调用?! - Amalo
好的,我检查一下,那么接收意图是什么?还是说我要如何注册该接收器? - Amalo
我对此不太了解,但是可以查看这个链接:http://stackoverflow.com/q/37110674/7320259 - Zaki Pathan
android.permission.GET_TASKS已被弃用 - Fay007

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