How to check if activity is in foreground or in visible background?
Asked Answered
H

25

128

I have a splash screen on a timer. My problem is that before I finish() my activity I need to check that the next activity has started because a system dialogue box pops-up and I only want to finish(); once the user has selected an option from the dialogue box?

I know that there are many questions on how to see if your activity is in the foreground but I do not know if this allows for dialogue boxes on top of the activity too.

Here is the problem, the red is my activity which is in the background while the dialogue is in the foreground:

the red is my activity which is in the background while the dialogue is in the foreground

EDIT: I have tried just not using finish() but then my activity can be gone back to in the stack of applications which I am trying to avoid.

Hargrave answered 3/8, 2013 at 23:45 Comment(6)
May be relevant: #4414671Fool
To clarify, you want to launch an intent chooser and wait for your app to finish() until after the user has tapped one of the choices? It sounds like you need Intent.createChooser() and startActivityForResult() followed by finish() when the result is received.Plover
possible duplicate of Checking if an Android application is running in the backgroundElectrodialysis
ProcessLifecycleOwner is the newest solutionElysia
@AlexMisiulia No, I'll let the votes do the talking - if your answer gets more votes I'll be happy to change the accepted answer.Hargrave
@Nick, I got your point. But the problem is that accepted answer is buggy as mentioned in comment to the answer and will work incorrectly for some cases. And more people will make mistakes and loose their time. But anyway, this is your choice)Herriot
H
76

UPD: updated to state Lifecycle.State.RESUMED. Thanks to @htafoya for that.

In 2019 with help of new support library 28+ or AndroidX you can simply use:

val isActivityInForeground = activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)

You can read more in the documenation to understand what happened under the hood.

Herriot answered 8/2, 2019 at 9:7 Comment(2)
Not really, probably it is better to place activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) or STARTED. INITIALIZED doesn't guarantee that it is in foreground.Candicecandid
For listener, use this instead: lifecycle.addObserver(object : LifecycleEventObserver { override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { if (event == Lifecycle.Event.ON_RESUME || event == Lifecycle.Event.ON_START || event == Lifecycle.Event.ON_CREATE) { Toast.makeText(this, "ON_RESUME", Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, "ON_PAUSE", Toast.LENGTH_SHORT).show() } } } )Underlinen
K
199

This is what is recommended as the right solution:

The right solution (credits go to Dan, CommonsWare and NeTeInStEiN) Track visibility of your application by yourself using Activity.onPause, Activity.onResume methods. Store "visibility" status in some other class. Good choices are your own implementation of the Application or a Service (there are also a few variations of this solution if you'd like to check activity visibility from the service).

Example Implement custom Application class (note the isActivityVisible() static method):

public class MyApplication extends Application {

  public static boolean isActivityVisible() {
    return activityVisible;
  }  

  public static void activityResumed() {
    activityVisible = true;
  }

  public static void activityPaused() {
    activityVisible = false;
  }

  private static boolean activityVisible;
}

Register your application class in AndroidManifest.xml:

<application
    android:name="your.app.package.MyApplication"
    android:icon="@drawable/icon"
    android:label="@string/app_name" >

Add onPause and onResume to every Activity in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended from MapActivity/ListActivity etc. you still need to write the following by hand):

@Override
protected void onResume() {
  super.onResume();
  MyApplication.activityResumed();
}

@Override
protected void onPause() {
  super.onPause();
  MyApplication.activityPaused();
}

In your finish() method, you want to use isActivityVisible() to check if the activity is visible or not. There you can also check if the user has selected an option or not. Continue when both conditions are met.

The source also mentions two wrong solutions...so avoid doing that.

Source: stackoverflow

Karns answered 27/8, 2013 at 15:25 Comment(9)
There is one little moment between finish and start activity and i thin need to add some delay and counterBulter
This doesn't work reliably. You might have the following situation: Resume A Resume B Pause A. Now activityVisible is false whereas the application is visible. Perhaps you use a visibility counter: visibleCounter ++ in onResume and visibleCounter -- in onPause.Willock
Agreed with Joris Weimar that this is not a foolproof solution. One scenario is if the user pulled down the notification panel, then neither the onPause, onStop, nor the onResume event is called. So what do you do then if none of these events are fired?!Boiney
In fact, none of the other answers work 100% either.Boiney
If app has more than one Activity this scheme won't work. Replace with counters at leastAlmost
This also doesn't work in the Android N split view case. One or the other of the activities will be paused, but visible.Abrahamsen
Case: As a library, you want to unregister your sensorlistener when the activity of a project, which imported you, is on background. Solution: Not approved since you can't control activities.Valli
It is not useful on HUAWEI P20 lite, when user use split screen....... (cry)...Miun
This will also not work on Screen Rotations: I discovered some time ago that my code using onStop/onResume stopped working for rotations. Reason was that (for performance reasons) FIRST the new version of the Activity got created and resumend and AFTER that the old version stopped and destroyed. You can use a variable with MyActivity.this.toString() and compare it to current value in onStop/onDestroy.Monstrosity
S
76

If targeting API level 14 or above, one can use android.app.Application.ActivityLifecycleCallbacks.

public class MyApplication extends Application implements ActivityLifecycleCallbacks {
    private static boolean isInterestingActivityVisible;

    @Override
    public void onCreate() {
        super.onCreate();
    
        // Register to be notified of activity state changes
        registerActivityLifecycleCallbacks(this);
        // ...
    }

    public boolean isInterestingActivityVisible() {
        return isInterestingActivityVisible;
    }

    @Override
    public void onActivityResumed(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = true;
        }
    }

    @Override
    public void onActivityStopped(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = false;
        }
    }

    // Other state change callback stubs
    // ...
}
Salpingotomy answered 24/7, 2014 at 13:57 Comment(3)
You could just do this in the regular activity lifecycle callbacks (onResume(), onStop()) too I would say.Quinquennium
@DanielWilson I think the point it is not to build a system for doing something where one already exists. IMHO this should be the accepted answer.Wheelock
This is great for checking if any of our activities are open. Far better than writing code in each one and risking missing something. Reliable and simple. Thanks!Aracelyaraceous
H
76

UPD: updated to state Lifecycle.State.RESUMED. Thanks to @htafoya for that.

In 2019 with help of new support library 28+ or AndroidX you can simply use:

val isActivityInForeground = activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)

You can read more in the documenation to understand what happened under the hood.

Herriot answered 8/2, 2019 at 9:7 Comment(2)
Not really, probably it is better to place activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) or STARTED. INITIALIZED doesn't guarantee that it is in foreground.Candicecandid
For listener, use this instead: lifecycle.addObserver(object : LifecycleEventObserver { override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { if (event == Lifecycle.Event.ON_RESUME || event == Lifecycle.Event.ON_START || event == Lifecycle.Event.ON_CREATE) { Toast.makeText(this, "ON_RESUME", Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, "ON_PAUSE", Toast.LENGTH_SHORT).show() } } } )Underlinen
V
14

Activity::hasWindowFocus() returns you the boolean you need.

public class ActivityForegroundChecker extends TimerTask
{
    private static final long FOREGROUND_CHECK_PERIOD = 5000;
    private static final long FIRST_DELAY             = 3000;

    private Activity m_activity;
    private Timer    m_timer;

    public ActivityForegroundChecker (Activity p_activity)
    {
        m_activity = p_activity;
    }

    @Override
    public void run()
    {
        if (m_activity.hasWindowFocus() == true) {
            // Activity is on foreground
            return;
        }
        // Activity is on background.
    }

    public void start ()
    {
        if (m_timer != null) {
            return;
        }
        m_timer = new Timer();
        m_timer.schedule(this, FIRST_DELAY, FOREGROUND_CHECK_PERIOD);
    }

    public void stop ()
    {
        if (m_timer == null) {
            return;
        }
        m_timer.cancel();
        m_timer.purge();
        m_timer = null;
    }
}

Here is an example class to check your activites' visibility from wherever you are.

Remember that if you show a dialog, the result will be false since the dialog will have the main focus. Other than that it's really handy and more reliable than suggested solutions.

Valli answered 5/1, 2018 at 11:17 Comment(6)
Thank you for amending the answer @Burak Day, it is actually an answer nowHargrave
This does not work, I would rather use a boolean property in the class, set to true in OnResume, and set to false in OnPause();Andri
@Andri what's the exact issue you are having with this code? Also which version?Valli
@Andri also, what if you don't have access to activity lifecycle methods. Consider you are just checking activity's visibility from a library.Valli
The real problem of this answer is it does NOT work, activity.hasWindowFocus is true can not guarantee the activity is between onResume and onPause state. I would rather recommend add an bool isResumed property in that activity, manually set the value and add a get method.Andri
@Andri onResule is called slightly BEFORE the activity is turned visible.Idell
R
10

That's exactly the difference between onPause and onStop events of the activity as described in the Activity class documentation.

If I understand you correctly, what you want to do is call finish() from your activity onStop to terminate it. See the attached image of the Activity Lifecycle Demo App. This is how it looks like when Activity B is launched from Activity A. The order of events is from bottom to top so you can see that Activity A onStop is called after Activity B onResume was already called.

Activity lifecycle demo

In case a dialog is shown your activity is dimmed in the background and only onPause is called.

Residential answered 26/8, 2013 at 14:52 Comment(0)
B
9

Two possible solutions :

  1. Activity LifeCycle Callbacks

Use an Application that implements ActivityLifecycleCallbacks and use it to track Activities lifecycle events in you application. Note that ActivityLifecycleCallbacks are for Android api >= 14. For previous Android api, you'll need to implement it by yourself inside all of your Activities ;-)

Use Application when you need to share / store states accross activities.

  1. Check for running process Informations

You can check the status of a running process with this class RunningAppProcessInfo

Fetch the running process list with ActivityManager.getRunningAppProcesses() and filter the result list to check for the desired RunningAppProcessInfo and check its "importance"

Beaudry answered 27/8, 2013 at 6:33 Comment(0)
F
3

Use the time gap between pause and resume from background to determine whether it is awake from background

In Custom Application

private static boolean isInBackground;
private static boolean isAwakeFromBackground;
private static final int backgroundAllowance = 10000;

public static void activityPaused() {
    isInBackground = true;
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if (isInBackground) {
                isAwakeFromBackground = true;
            }
        }
    }, backgroundAllowance);
    Log.v("activity status", "activityPaused");
}

public static void activityResumed() {
    isInBackground = false;
    if(isAwakeFromBackground){
        // do something when awake from background
        Log.v("activity status", "isAwakeFromBackground");
    }
    isAwakeFromBackground = false;
    Log.v("activity status", "activityResumed");
}

In BaseActivity Class

@Override
protected void onResume() {
  super.onResume();
  MyApplication.activityResumed();
}

@Override
protected void onPause() {
  super.onPause();
  MyApplication.activityPaused();
}
Foraminifer answered 25/6, 2014 at 3:56 Comment(0)
R
3

I think I have better solution. Because you can build in simply MyApplication.activityResumed(); to every Activity by one extend.

Firstly you have to create (like CyberneticTwerkGuruOrc)

public class MyApplication extends Application {

  public static boolean isActivityVisible() {
    return activityVisible;
  }  

  public static void activityResumed() {
    activityVisible = true;
  }

  public static void activityPaused() {
    activityVisible = false;
  }

  private static boolean activityVisible;
}

Next, you have to add Application class to AndroidManifest.xml

<application
    android:name="your.app.package.MyApplication"
    android:icon="@drawable/icon"
    android:label="@string/app_name" >

Then, create class ActivityBase

public class ActivityBase extends Activity {

    @Override
    protected void onPause() {
        super.onPause();
        MyApplication.activityPaused();
    }

    @Override
    protected void onResume() {
        super.onResume();
        MyApplication.activityResumed();
    }
}

Finally, when you crate new Activity, you can simply extends it by ActivityBase instead of Activity.

public class Main extends ActivityBase {
    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }
}

For me It's better method cause you have to just remember about extend by ActivityBase. In addition you can expand your base function in future. In my case I added receivers for my service and alerts about network in one class.

If you wanna check visibility of your App, you can simply call

MyApplication.isActivityVisible()
Rainstorm answered 26/2, 2016 at 11:4 Comment(1)
What if I need my Activities to extend the AppCombatActivity?Campman
L
2

This can achieve this by a efficient way by using Application.ActivityLifecycleCallbacks

For example lets take Activity class name as ProfileActivity lets find whether its is in foreground or background

first we need to create our application class by extending Application Class

which implements

Application.ActivityLifecycleCallbacks

Lets be my Application class as follows

Application class

public class AppController extends Application implements Application.ActivityLifecycleCallbacks {


private boolean activityInForeground;

@Override
public void onCreate() {
    super.onCreate();

//register ActivityLifecycleCallbacks  

    registerActivityLifecycleCallbacks(this);
   
}



public static boolean isActivityVisible() {
    return activityVisible;
}

public static void activityResumed() {
    activityVisible = true;
}

public static void activityPaused() {
    activityVisible = false;
}

private static boolean activityVisible;

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

}

@Override
public void onActivityStarted(Activity activity) {

}

@Override
public void onActivityResumed(Activity activity) {
    //Here you can add all Activity class you need to check whether its on screen or not

    activityInForeground = activity instanceof ProfileActivity;
}

@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) {

}

public boolean isActivityInForeground() {
    return activityInForeground;
}
}

in the above class there is a override methord onActivityResumed of ActivityLifecycleCallbacks

 @Override
public void onActivityResumed(Activity activity) {
    //Here you can add all Activity class you need to check whether its on screen or not

    activityInForeground = activity instanceof ProfileActivity;
}

where all activity instance which is currently displayed on screen can be found, just check whether Your Activity is on Screen or not by the above method.

Register your Application class in manifest.xml

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

To check weather Activity is Foreground or background as per the above solution call the following method on places you need to check

AppController applicationControl = (AppController) getApplicationContext();
    if(applicationControl.isActivityInForeground()){
     Log.d("TAG","Activity is in foreground")
    }
    else
    {
      Log.d("TAG","Activity is in background")
    }
Labile answered 8/3, 2016 at 13:30 Comment(0)
P
2

If you want to know if any activity of your app is visible on the screen, you can do something like this:

public class MyAppActivityCallbacks implements Application.ActivityLifecycleCallbacks {
private Set<Class<Activity>> visibleActivities = new HashSet<>();

@Override
public void onActivityResumed(Activity activity) {
    visibleActivities.add((Class<Activity>) activity.getClass());
}

@Override
public void onActivityStopped(Activity activity) {
     visibleActivities.remove(activity.getClass());
}

public boolean isAnyActivityVisible() {
    return !visibleActivities.isEmpty();
}

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

@Override
public void onActivityStarted(Activity activity) {}

@Override
public void onActivityPaused(Activity activity) {}

@Override
public void onActivityDestroyed(Activity activity) {}

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

Just create a singleton of this class and set it in your Application instance like below:

class App extends Application{
     @Override
     public void onCreate() {
         registerActivityLifecycleCallbacks(myAppActivityCallbacks);
     }
}

Then you can use isAnyActivityVisible() method of your MyAppActivityCallbacks instance everywhere!

Peatroy answered 15/6, 2018 at 17:7 Comment(1)
I think this is a nice solution, although why the need to keep a set of the activity classes? why not simply use a counter and increase/decrease it on resume/paused, and then check if == 0?Guarnerius
E
1

Save a flag if you are paused or resumed. If you are resumed it means you are in the foreground

boolean  isResumed = false;

@Override
public void onPause() {
  super.onPause();    
  isResumed = false;
}

@Override
public void onResume() {
  super.onResume();    
  isResumed = true;
}

private void finishIfForeground() {
  if (isResumed) {
    finish();
  }
}
Everetteeverglade answered 26/8, 2013 at 15:10 Comment(0)
J
1

Would Activity.onWindowFocusChanged(boolean hasFocus) be useful here? That, plus a class-level flag, something like isFocused that onWindowFocusChanged sets, would be an easy way to tell at any point in your activity if it is focused or not. From reading the docs, it looks like it would properly set "false" in any situation where the activity isn't directly in the physical "foreground", like if a dialog is being displayed or the notification tray is pulled down.

Example:

boolean isFocused;
@Override
void onWindowFocusChanged (boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    isFocused = hasFocus;
}

void someMethod() {
    if (isFocused) {
        // The activity is the foremost object on the screen
    } else {
        // The activity is obscured or otherwise not visible
    }
}
Jackijackie answered 16/11, 2017 at 18:59 Comment(1)
This answer should be the accepted one. onResume() is called before the activity is visible.Idell
N
1

If you are using EventBus, it as a method called hasSubscriberForEvent which can be used to check if an Activity is focused.

Nonperformance answered 29/4, 2020 at 22:15 Comment(2)
Project does not seem to be maintained, anymore.Tailrace
I don't think there is much to maintain since it does one specific thing. It still works though.Nonperformance
M
1

I wanted to mention a modification. Activity.onPause kicks in even if your app is still partly visible (may be a system dialog box over it or split screen).

Maybe you'd want paused still count as visible and only count stopped/destroyed as invisible.

They you have a problem when your activity can restart (I have a restart button to counter some errors that don't occur often).

Even if it is the same activity it will not be destroyed before recreation but be handled like transitioning to another app:

This is not a direct answer to the question at hand but I noticed that the lifecycle displayed above is also true if you just terminate and restart the SAME activity (using a restart Button in a fragment in my case). This is true for Android 10 at least.

Restart process looks like this also: MainActivity (old) .onPause MainActivity (new) .onCreate MainActivity (new) .onStart MainActivity (new) .onResume MainActivity (old) .onStop MainActivity (old) .onDestroy

Now if you would set the visibility in onStop this has happened after onResume of the newer Instance of the activity and you wrongly get visibility false.

To counter that you can set a static string id in onCreate:

private static String instanceId = MainActivity.this.toString();

Then in onStop you can use

if(instanceId == null || instanceId.equals(MainActivity.this.toString()))
    setVisibility(false);
//else: visibility stays unchanged
Monstrosity answered 29/4, 2021 at 10:27 Comment(0)
S
0

did you try not calling finish, and putting "android:noHistory="true" in the manifest? this will prevent the activity from going to the stack.

Schnapp answered 20/8, 2013 at 23:41 Comment(0)
P
0

I have to say your workflow is not in a standard Android way. In Android, you don't need to finish() your activity if you want to open another activity from Intent. As for user's convenience, Android allows user to use 'back' key to go back from the activity that you opened to your app.

So just let the system stop you activity and save anything need to when you activity is called back.

Protractor answered 24/8, 2013 at 11:59 Comment(2)
"buu this is not the android" way answers are tiresome and don't answer the question posed in the first place. furthermore, there are valid reasons to finish(); - for example it's conceivable that going back to it once the action has taken hold serves no purpose whatsoever. in other words, do you think they put finish() in there for fun? it staying on the stack is exactly what the question asker wanted to avoidTubb
"buu this is not the android" way answers are tiresome and don't answer the question posed in the first place. Your commend was unfair. Although I pointed it out this was not Android way, I gave the answer after this sentence instead of nothing. I just didn't give the answer in code as that was unnecessary. So it was unfair saying I didn't answer the question in the first place.Protractor
B
0

One possible solution might be setting a flag while showing the system-dialog and then in the onStop method of the activity life-cycle, check for the flag, if true, finish the activity.

For example, if the system dialog is triggered by some buttonclick, then the onclick listener might be like

private OnClickListener btnClickListener = new OnClickListener() {

    @Override
    public void onClick(View v) {           
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_SEND);
        intent.setType("text/plain");
        CheckActivity.this.startActivity(Intent.createChooser(intent, "Complete action using"));
        checkFlag = true;  //flag used to check

    }
};

and in onstop of activity:

@Override
protected void onStop() {
    if(checkFlag){
        finish();
    }
    super.onStop();
}
Bigamy answered 27/8, 2013 at 7:15 Comment(0)
T
0

Why not use broadcasts for this? the second activity (the one that needs to be up) can send a local broadcast like this:

//put this in onCreate(..) or any other lifecycle method that suits you best
//notice the string sent to the intent, it will be used to register a receiver!
Intent result = new Intent("broadcast identifier");
result.putString("some message");//this is optional
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(result);

then write a simple receiver within the splash activity:

//this goes on the class level (like a class/instance variable, not in a method) of your splash activity:
private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        //kill activity here!!!
        //mission accomplished!
    }
};

and register your new receiver with the LocalBroadcastManager to listen to the broadcast from your second activity:

//notice the string sent to the intent filter, this is where you tell the BroadcastManager which broadcasts you want to listen to!
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(receiver, new IntentFilter("broadcast identifier"));

NOTE that you could use a constant or a string resource for the "broadcast identifier" string.

Trevino answered 27/8, 2013 at 12:55 Comment(1)
For better security ad efficiency use LocalBroadcastManager hereValkyrie
M
0

If you use finish() just to avoid new app to starts in the stack (task) of you app, you can use Intent.FLAG_ACTIVITY_NEW_TASK flag, when starting new application and do not call finish() at all. According to the documentation, this is the flag to be used to implement a "launcher" style behavior.

// just add this line before you start an activity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Mansur answered 27/8, 2013 at 16:0 Comment(0)
H
0

Use these methods inside of an Activity.

isDestroyed()

Added in Api 17
Returns true if the final onDestroy() call has been made on the Activity, so this instance is now dead.

isFinishing()

Added in Api 1
Check to see whether this activity is in the process of finishing, either because you called finish() on it or someone else has requested that it finished. This is often used in onPause() to determine whether the activity is simply pausing or completely finishing.


From Memory Leaks Documentation

A common mistake with AsyncTask is to capture a strong reference to the host Activity (or Fragment):

class MyActivity extends Activity {
  private AsyncTask<Void, Void, Void> myTask = new AsyncTask<Void, Void, Void>() {
    // Don't do this! Inner classes implicitly keep a pointer to their
    // parent, which in this case is the Activity!
  }
}

This is a problem because AsyncTask can easily outlive the parent Activity, for example if a configuration change happens while the task is running.

The right way to do this is to make your task a static class, which does not capture the parent, and holding a weak reference to the host Activity:

class MyActivity extends Activity {
  static class MyTask extends AsyncTask<Void, Void, Void> {
    // Weak references will still allow the Activity to be garbage-collected
    private final WeakReference<MyActivity> weakActivity;

    MyTask(MyActivity myActivity) {
      this.weakActivity = new WeakReference<>(myActivity);
    }

    @Override
    public Void doInBackground(Void... params) {
      // do async stuff here
    }

    @Override
    public void onPostExecute(Void result) {
      // Re-acquire a strong reference to the activity, and verify
      // that it still exists and is active.
      MyActivity activity = weakActivity.get();
      if (activity == null
          || activity.isFinishing()
          || activity.isDestroyed()) {
        // activity is no longer valid, don't do anything!
        return;
      }

      // The activity is still valid, do main-thread stuff here
    }
  }
}
Henequen answered 15/3, 2017 at 5:4 Comment(0)
T
0

Here is a solution using Application class.

public class AppSingleton extends Application implements Application.ActivityLifecycleCallbacks {

private WeakReference<Context> foregroundActivity;


@Override
public void onActivityResumed(Activity activity) {
    foregroundActivity=new WeakReference<Context>(activity);
}

@Override
public void onActivityPaused(Activity activity) {
    String class_name_activity=activity.getClass().getCanonicalName();
    if (foregroundActivity != null && 
            foregroundActivity.get().getClass().getCanonicalName().equals(class_name_activity)) {
        foregroundActivity = null;
    }
}

//............................

public boolean isOnForeground(@NonNull Context activity_cntxt) {
    return isOnForeground(activity_cntxt.getClass().getCanonicalName());
}

public boolean isOnForeground(@NonNull String activity_canonical_name) {
    if (foregroundActivity != null && foregroundActivity.get() != null) {
        return foregroundActivity.get().getClass().getCanonicalName().equals(activity_canonical_name);
    }
    return false;
}
}

You can simply use it like follows,

((AppSingleton)context.getApplicationContext()).isOnForeground(context_activity);

If you have a reference to the required Activity or using the canonical name of the Activity, you can find out whether it's in the foreground or not. This solution may not be foolproof. Therefore your comments are really welcome.

Tessler answered 29/9, 2017 at 11:14 Comment(0)
D
0

I don't know why nobody talked about sharedPreferences, for Activity A,setting a SharedPreference like that (for example in onPause() ) :

SharedPreferences pref = context.getSharedPreferences(SHARED_PREF, 0);
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("is_activity_paused_a", true);
editor.commit();

I think this is the reliable way to track activities visibilty.

Doerr answered 31/10, 2017 at 22:40 Comment(1)
No body like to use SharedPreferences when checking live events. I think processing time is some how longer.Ellerd
F
0

Since here you have explicitly asked for an Activity. I added a simple static method in my Utils class to get the state of the activity by passing the activity.

    public static boolean isActivityVisible(Activity mActivity) {
    if (mActivity != null) {
        Class klass = mActivity.getClass();
        while (klass != null) {
            try {
                Field field = klass.getDeclaredField("mResumed");
                field.setAccessible(true);
                Object obj = field.get(mActivity);
                return (Boolean)obj;
            } catch (NoSuchFieldException exception1) {
            Log.e(TAG, exception1.toString());
            } catch (IllegalAccessException exception2) {
            Log.e(TAG, exception2.toString());
            }
            klass = klass.getSuperclass();
        }
    }
    return false;
}
Feasible answered 30/3, 2021 at 17:35 Comment(0)
P
0

I found a very simple way of checking if an activity is in the foreground or in the background. In my case, I need to find a way of showing only on cold start, the com.google.android.gms.settings.ADS_PRIVACY page for opting in or out of personalized ads; resetting, enabling or disabling Advertising ID that is required by local state laws for Consumer Data Privacy/Protection affecting users of my app in California, Utah, Oregon and some other states in the USA. My solution is to create a global variable in the app.java or myApp.java. I only need to know if my app's start menu activity is running in the background to prevent the settings page from showing during soft start, opening the start menu from other activities, resuming the start menu activity after closing an appOpen Ad or closing the settings page. See the code snippet below for my app's StartMenuActivity.java below. I hope it helps.

public class startMenuActivity extends AppCompatActivity {

    // other code snippets here
    // ...................

    boolean isAppInBackground;

    @Override
    protected void onCreate(Bundle SaveInstanceState) {
        super.onCreate(SaveInstanceState);
        setContentView(layout.start_menu);

        isAppInBackground = 
        ((myApp)this.getApplication()).getIsAppInBackground();
            if (!isAppInBackground) {
            showCCPAConsentDialog();
        }

        // other code snippets here
        // ...................
    }

    @Override
    protected void onStop() {
        Log.d("ACTIVITYSTAT", "StartMenuActivity is in the background");
        ((myApp)this.getApplication()).setIsAppInBackground(true);
        super.onStop();

    }

    @Override
    protected void onResume() {
        Log.d("ACTIVITYSTAT", "StartMenuActivity is in the foreground");
        /* code snippet for your global variable to indicate that your 
        app activity is in the foreground */
 
        super.onResume();
    }
}
Pollux answered 8/7, 2023 at 7:30 Comment(0)
F
-4

I used to do like,

if the activity is not in the foreground

getIntent()

will return null. :=P

Franchot answered 23/6, 2014 at 14:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.