Android checking whether the app is closed
Asked Answered
P

6

6

I have an android application i need one function or any broadcast receiver that can check if the app is closed.. i don't need to call on destroy in every activity (there is about 20 activity into the app) i tried to add this function in Application class

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

Also i have registered in on create in Application class

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

but the onPaused and onResumed and onDestroyed function is called when i switch between activity: because it detects whether any activity is closed or destroyed or even resumed

so any solution to check whether the app is closed in one function??

Polaroid answered 3/3, 2017 at 10:42 Comment(4)
https://mcmap.net/q/82960/-how-to-detected-if-application-is-closed/7320259 try thisChamperty
what you want to check if the app is in foreground or background?Biserrate
i want a listener that receive something when the app is closed by user either by pressing back or home buttonPolaroid
ProcessLifecycleOwner is the newest solutionOvermuch
O
14

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

Overmuch answered 14/2, 2019 at 7:3 Comment(1)
Hi S.R. How to bring the app back to the foreground? So, it always on foreground whenever Recent Apps and Home button is pressed,Lavinia
C
6

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://mcmap.net/q/82471/-check-android-application-is-in-foreground-or-not-duplicate

Colton answered 19/1, 2018 at 12:53 Comment(1)
this gets invoked after minutes, otherwise would have been perfect :(Erinerina
M
4

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);
}
Midcourse answered 14/2, 2019 at 13:22 Comment(2)
It did work only when the app is cleared from recent apps.Lumbard
onTaskRemoved() is not getting invoked at allErinerina
K
2

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.

Kenwee answered 3/3, 2017 at 10:46 Comment(1)
Deprecated .....ProcessLifecycleOwner which is a part of Android Architecture Component is prefered. a kotlin sample project demonstrating usage of ProcessLifecycleOwner is hereOvermuch
D
1

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

Dyslogistic answered 22/2, 2019 at 8:37 Comment(1)
With this code you will get when the app get to background and not only when it is closed. I suggest to de-allocate all components when the app gets to background and then re-allocate when app go to foreground.Dyslogistic
C
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;
    }

}  

Add this permission too

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

try this hope it helps

Champerty answered 3/3, 2017 at 10:54 Comment(4)
this function must be called every 1 sec??!Polaroid
ok i check it, so what is the intent to receive ? or how to i register this receiver ?Polaroid
I don't know much about that. but check this https://mcmap.net/q/82961/-broadcast-receiver-on-app-closed-or-in-the-background/7320259Champerty
android.permission.GET_TASKS is deprecatedGobbledygook

© 2022 - 2024 — McMap. All rights reserved.