59
votes

I have implemented a BroadcastReceiver which is triggered by the AlarmManager. The AlarmManager is initialized on BOOT_COMPLETED. So i have to declare the receiver in the manifest.

My problem is that i want the BroadcastReceiver only to do something when none of my own activities are in the foreground (aka the user is not interacting with my application). I pull information from a remote server and don't want to notify the user if he is currently in my application anyways.

So far i have not managed to find a way to determine if my application is in the foreground. Is there a way to do such thing? The ActivityManager tells me if my application is running but not whether it is in the foreground.

The problem is pretty much the same as described here: Inform Activity from a BroadcastReceiver ONLY if it is in the foreground

SOLUTION:

After evaluating several solutions i want to quickly outline what i think is the best method to deal with activities in the background/foreground.

The preferred way is to register a broadcast receiver in the onResume method of your activity and to deregister it on the activities on onPause. Any service or other background element will than need to send a broadcast intent with a specific action that your activity will intercept.

If your activity is in the foreground it will have its intent receiver registered and is able to directly deal with the intent send from your service. If it is not in the foreground it will not receive the intent but the service that invokved the broadcast will know that nobody intercepted its broadcast intent and will be able to deal with that itself. Eg it could than launch the desired activity, show a notification etc.

7
"the service that invoked the broadcast will know that nobody intercepted its broadcast intent" - possibly a stupid question but how will it know?ostergaard
@ajostergaard I think it goes like that: Broadcast sent "are you in foregraund" intent. When Activity is in foreground it can recieve that intent (because registers own recevier in onResume) and respones with Intent "yes, I'm in foreground". Broadcast can revevie that, thus know about Activity state. BTW. Check my answer for this question below :)klimat
ProcessLifecycleOwner is the newest solutionS.R

7 Answers

27
votes

The following answer: "Is application running in background", summarizes solutions available for background/foreground checking.

Note:
Previously this answer suggested to use ActivityManager.getRunningAppProcesses(), however that method appeared to be not completely reliable and its usage is discouraged. Check the link above for the details.

12
votes

Your activity can track its own state as to whether it is in the foreground (set boolean to true in onStart(), to false in onStop()). Alas, that boolean is not provided to you by Activity automatically.

4
votes

ActivityManager#getRunningAppProcesses() returns a List of RunningAppProcessInfo. Each RunningAppProcessInfo has a field called importance. importance equal to RunningAppProcessInfo.IMPORTANCE_FOREGROUND seems to show which activity is actively being observed by the user. There is also RunningAppProcessInfo.IMPORTANCE_VISIBLE which is lower but might be worth checking out.

3
votes

check out my solution for determining if an activity is in the foreground: http://www.mannaz.at/codebase/android-activity-foreground-surveillance/

It should be easy to revert the logic from "in the foreground" to "not in the foreground".

3
votes

I have implemented a BroadcastReceiver which is triggered by the AlarmManager. The AlarmManager is initialized on BOOT_COMPLETED. So i have to declare the receiver in the manifest.

My problem is that i want the BroadcastReceiver only to do something when none of my own activities are in the foreground (aka the user is not interacting with my application). I pull information from a remote server and don't want to notify the user if he is currently in my application anyways.

So far i have not managed to find a way to determine if my application is in the foreground. Is there a way to do such thing? The ActivityManager tells me if my application is running but not whether it is in the foreground.

There doesn't seem to be a direct way to determine if one of your activities is the current running foreground activity. However, you can get the desired effect by using an ordered broadcast and two broadcast receivers. One broadcast receiver needs to be registered in OnResume() and unregistered in OnPause(). The 2nd broadcast receiver will be declared in your manifest as you've already done. Set the android:priority for your receivers such that if the dynamically registered receiver is registered, it will receive the intent first, then you can eat the intent so that the broadcast receiver you registered in your manifest is never notified.

1
votes

You can test if the window has focus - but as stated in dev docs this is not the same as if activity is in foreground.

1
votes

I'd use ActivityLifecycleCallbacks to get much cleaner solution.

It can be insecure, read this before you decided to use example below in production. It works in 'home development' for my device and OS version.

public class App extends Application implements Application.ActivityLifecycleCallbacks {

private boolean inForeground;

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

@Override
public void onActivityResumed(Activity activity) {
    inForeground = activity instanceof YourActivity;
}

public boolean isInForeground() {
    return inForeground;
}

Register App in AndroidManifest:

<application
        android:name=".App" />

And the final piece of the puzzle:

public class YourReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        App app = (App) context.getApplicationContext();
        if(app.isInForeground()){
            // do some stuff
        }
    }
}