1

My problem is I have a SplashActivity that runs each time app is launched and when a notification is received when app is in the background I start the SplashActivity (that how it works now and it works but it gives the feeling the app is relaunched every time user responds to a notification and some unnecessary server updates are happening).

What I want to do is:

if (app is in background) {
    if (running) {
        launch SomeActivity
    } else {
        launch SplashActivity
    }
}

I went over a lot of posts and none of them helped me to reliably know when the app is running (I consider running in the background as running).

I'm able to detect wether app is in foreground or background (that's not a problem) but my problem is detecting "terminated" state.

I looked in to ActivityLifecycleCallbacks in Application but I can't see how it can reliably help me because onDestroy is not guaranteed to be called.

Anyone solved this issue?

Thanks

Edit:

I ended up using solution suggested in Google I/O 2016 video to detect background and foreground state and added a small addition in onActivityDestroyed to detect my main activity onDestory

It's not perfect and could get the "app state" wrong if onDestory of main tabs activity isn't called but this is what I ended up doing:

public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks {

    public static final int APP_STATE_FOREGROUND = 1000;
    public static final int APP_STATE_BACKGROUND = 1001;
    public static final int APP_STATE_TERMINATED = 1002;

    private int mNumStarted;
    private int mAppState;

    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(this);
        // set default app state to APP_STATE_TERMINATED in case app state is not certain so app will launch as if it is a new app launch when opened from push notification
        mAppState = APP_STATE_TERMINATED; 

    }

    public int getAppState() {
        return mAppState;
    }

    /**
     * Application.ActivityLifecycleCallbacks interface methods
     */
    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        String activityName = activity.getLocalClassName();
        if (activityName.equals("main.TabsActivity")) {
            mAppState = APP_STATE_FOREGROUND;
        }
    }

    @Override
    public void onActivityStarted(Activity activity) {
        if (mNumStarted == 0) {
            mAppState = APP_STATE_FOREGROUND;
        }
        mNumStarted++;
    }

    @Override
    public void onActivityResumed(Activity activity) {}

    @Override
    public void onActivityPaused(Activity activity) {}

    @Override
    public void onActivityStopped(Activity activity) {
        mNumStarted--;
        if (mNumStarted == 0) {
            mAppState = APP_STATE_BACKGROUND;
        }
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
        String activityName = activity.getLocalClassName();
        if (activityName.equals("main.TabsActivity")) {
            mAppState = APP_STATE_TERMINATED;
        }
    }
}

This solution works for me (for now), maybe it will help someone else.

Guy S
  • 1,424
  • 1
  • 15
  • 34
  • https://stackoverflow.com/questions/43779809/how-to-check-if-an-android-application-is-running-in-the-background-or-in-foregr – IntelliJ Amiya Jul 17 '17 at 12:25
  • I said: "I'm able to detect wether app is in foreground or background (that's not a problem) but my problem is detecting "terminated" state." – Guy S Jul 17 '17 at 12:28
  • `terminated` means . App is not background ? right – IntelliJ Amiya Jul 17 '17 at 12:34
  • Yes (not in background and not in foreground) – Guy S Jul 17 '17 at 12:35
  • I guess you want to get Message on that time ?? `onMessageReceived` is not calling ?? – IntelliJ Amiya Jul 17 '17 at 12:37
  • if lets say OS kills the app won't the services be stopped as well and I won't get onMessageReceived? Maybe I wasn't very clear in the question. I can track app foreground/background state using ActivityLifecycleCallbacks. But I also need to keep track of when activities are created and destroyed and if "SomeActivity" is destroyed and a notification is received launch SplashActivity, however, I can't really reliably count on onDestroy calls, so for now I just launch SplashActivity every time – Guy S Jul 17 '17 at 12:56
  • Did you try my answer? – Fatih Santalu Jul 19 '17 at 07:48
  • Not yet, had to attend to other issus, hopefully will return to it later today – Guy S Jul 20 '17 at 09:25
  • @Guy S [1] You may need to update your solution if an Android app has multiple Activity objects; [2] I would be surprised if your approach for determining the "terminated" state works, because from my experience method onActivityDestroyed() is rarely, if not never, called. FYI, I'm also trying to find a solution, but so far without success. It appears that Android does not want to provide this type of information for security reasons. – jonathanzh Aug 22 '18 at 19:32

2 Answers2

1

Method 1: You can safely use below approach on your release applications aswell. These methods are self explanatory. But isAppVisible() indicates your app is currently running either in background or foreground the otherwise likely it means app is terminated by system. I also put some logs for you to debug if it's working as expected or not.

public class MyApplication extends Application {

    private static final String TAG = MyApplication.class.getSimpleName();
    private int mVisibleCount;
    private boolean mInBackground;

    @Override public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            }

            @Override public void onActivityStarted(Activity activity) {
                mVisibleCount++;
                if (mInBackground && mVisibleCount > 0) {
                    mInBackground = false;
                    Log.i(TAG, "App in foreground");
                }
            }

            @Override public void onActivityResumed(Activity activity) {
            }

            @Override public void onActivityPaused(Activity activity) {
            }

            @Override public void onActivityStopped(Activity activity) {
                mVisibleCount--;
                if (mVisibleCount == 0) {
                    if (activity.isFinishing()) {
                        Log.i(TAG, "App is finishing");
                    } else {
                        mInBackground = true;
                        Log.i(TAG, "App in background");
                    }
                }
            }

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

            }

            @Override public void onActivityDestroyed(Activity activity) {
            }
        });
    }

    public boolean isAppInBackground() {
        return mInBackground;
    }

    public boolean isAppVisible() {
        return mVisibleCount > 0;
    }

    public int getVisibleCount() {
        return mVisibleCount;
    }
}

Method 2: There's another method using Service to detect if application is terminated. See link

Fatih Santalu
  • 4,641
  • 2
  • 17
  • 34
  • I based my solution on a different source but it's similar to what you suggested in your answer. so thanks and +1 – Guy S Jul 24 '17 at 05:36
-1

here the method to know application is in background or not

 public boolean isApplicationBroughtToBackground() {
        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
        if (!tasks.isEmpty()) {
            ComponentName topActivity = tasks.get(0).topActivity;
            if (!topActivity.getPackageName().equals(getPackageName())) {
                return true;
            }
        }
        return false;
    }
Hitesh Gehlot
  • 1,307
  • 1
  • 15
  • 30
  • getRunningTasks is deprecated from lollipop and up. and shouldn't be used for this purpose anyway (that's at least what I understand from the docs). Also I stated that i have no problem detecting if the app is in the background... – Guy S Jul 17 '17 at 12:27