1

What i'm trying to achieve is that when i close my app from recents i can still control my apps through my notification.

All works well but when i click the close button in my notification when my application is still running i get alot of NPE's.

Code that gets executed when close button in notification is clicked:

mMediaSessionCompat.setCallback(new MediaSessionCompat.Callback() {
        @Override
        public void onStop() {
            super.onStop();
            Main.unbindService(getApplicationContext());
            stopSelf();
            Log.d(TAG,"stop!");
}

Now when i close my application and then destroy my Service through the notification all works perfectly.

So my question is how i can determine when my application is still running ( visible for the user or in the background(recent apps) and when it gets destroyed and only the notification is present?

So then i can create if statements to only call stopSelf(); when the app is destroyed and don't call it when my application is still running.

Vince VD
  • 1,506
  • 17
  • 38

1 Answers1

0

Perhaps the Application.registerActivityLifecycleCallbacks() method might be of use to you. You could put something like this in your application's onCreate() method:

registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
        int activityCount = 0;

        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            activityCount++;
        }

        @Override
        public void onActivityStarted(Activity activity) {}

        @Override
        public void onActivityResumed(Activity activity) {}

        @Override
        public void onActivityPaused(Activity activity) {}

        @Override
        public void onActivityStopped(Activity activity) {}

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

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

and use it to keep track of whether any of your activities are still running.

EDIT: Ok, if you want to avoid the situation where a finished activity keeps hanging for some time before the onDestroyed() method is called, you can use a bit more advanced approach, where you check whether the activity is finishing in the onActivityPaused and onActivityStopped. So you make a class like this:

private class ActivityWatcher implements Application.ActivityLifecycleCallbacks {

    //a set of currently running activities
    private Set<Activity> activities = new HashSet<>();

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        activities.add(activity);
    }

    @Override
    public void onActivityStarted(Activity activity) {}

    @Override
    public void onActivityResumed(Activity activity) {}

    @Override
    public void onActivityPaused(Activity activity) {
        if (activity.isFinishing()) {
            activities.remove(activity);
        }
    }

    @Override
    public void onActivityStopped(Activity activity) {
        if (activity.isFinishing()) {
            activities.remove(activity);
        }
    }

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

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

    public boolean isAnyActivityRunning() {
        return !activities.isEmpty();
    }
}

and then in your application class you create an instance and register it as activity lifecycle callback:

public class MyApplication extends Application {

    private ActivityWatcher activityWatcher = new ActivityWatcher();

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

    public boolean isAppAlive() {
        return activityWatcher.isAnyActivityRunning();
    }
}

Should work.

Michal Dvorak
  • 322
  • 1
  • 7
  • OnDestroy does not always get called, so that's not a safe way to check if my activity is still running. – Vince VD Jun 13 '19 at 10:37
  • If your activity is not destroyed, then it's still running, no? Anyway, if you're concerned that it might take a long time before a finished activity is actually destroyed, you could make a check in the `onActivityPaused` whether the activity is finishing (call `activity.isFinishing()`) and handle it the same as activity being destroyed. Of course in that case you couldn't use a simple counter because you could decrement it twice for a single activity. Instead you would need to keep track of _which_ activity is finishing and/or being destroyed. – Michal Dvorak Jun 13 '19 at 10:51
  • But it seems that there can be a situation where onDestroy doesn't get called. https://stackoverflow.com/a/19608985 – Vince VD Jun 13 '19 at 11:32
  • And if that happens my app would crash which would give a bad user experience. – Vince VD Jun 13 '19 at 11:33
  • Yeah, the onDestroy won't be called if the OS kills your whole process. But if that happens, you service will be called as well so the whole point is moot, no? – Michal Dvorak Jun 13 '19 at 12:03
  • my onDestroy doesn't get called when i remove the app from my recent apps for some reason but sometimes it does gets called? – Vince VD Jun 13 '19 at 12:07