Android checking whether the app is closed

僤鯓⒐⒋嵵緔 提交于 2019-11-28 01:45:42

This answer uses ProcessLifecycleOwner to detect application visibility.

which is a part of Android Architecture Component .


1. add this lib to your project

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

2. Extend an application class that implements 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);
    }

}

And use it like this:

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

Don't forget to add application name into your manifest

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

Done.


(Kotlin example)

https://github.com/jshvarts/AppLifecycleDemo

You can use this function to determine if the app is closed ( not in background nor in the foreground).

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
}

You can also check if the app is in foreground by using this function: https://stackoverflow.com/a/8490088/9005188

Basically looking at your problem, you want to track the state changes in an app.

It can be quite difficult to get it right taking care of all the use cases. But there is an amazing library which works very well and is super-easy to use - RxAppState.

I have been using this library for quite a long time now and it works very well in all cases. I highly recommend you to try this.

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;
    }

}  

Add this permission too

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

try this hope it helps

Like @S.R answer, you can also use the interface "Application.ActivityLifecycleCallbacks" in ur custom application, and then in the "onActivityStopped" use the "isAppOnForeground(Context)" method.

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...]

This is called every time the app goes in background and not when it get closed. If you put the "isAppOnForeground" inside the "onActivityDestroyed" it won't work with the code above for "isAppOnForeground" because it can't find the process (I think), maybe changing the code above or with another implementation it will work. The "onActivityDestroyed" will get called when the app is closed, so if you can check if the app is in background when it is called (so the app is already closed) you can grep exactly the moment when the app is being closed.

Code of "isAppOnForeground" (I'm using it in a Utils static class):

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;
    }

Hope this is helpful, see you bye and happy coding ! :D

TakeInfo

use one service which is start from Application class.

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;
    }
}

start this service from Application class.

@Override
public void onCreate() {
    super.onCreate();
    Intent intent = new Intent(getApplicationContext(), AppService.class);
    startService(intent);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!