What's the proper way to initialize an Android application? - android

Problem: I need to run some code at every start before my app is ready to be used.
At first, I tried doing it in a dedicated activity.
AndroidManifest.xml
<activity android:name=".MainActivity" />
<activity android:name=".StarterActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
AppLoader.java
public class AppLoader {
private static Object someInstance;
public static void load(Runnable onCompleteCallback) {
try {
someInstance = new Object();
//potentially long operation to initialize the app
Thread.sleep(5000);
onCompleteCallback.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void checkInitialized() {
if (someInstance == null) {
throw new RuntimeException("Not initialized");
}
}
}
StarterActivity.java
public class StarterActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppLoader.load(() -> {
MainActivity.start(this);
finish();
});
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static void start(Context context) {
Intent starter = new Intent(context, MainActivity.class);
context.startActivity(starter);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppLoader.checkInitialized();
}
}
This works fine if the app is cold started via the launcher icon but crashes in all other cases. Simple way to reproduce the issue:
Go to developer settings on your device and set "Background process limit" to "No background process"
Open the app
Open some other app
Open the app again. Result: it crashes.
Here's an article describing a similar problem: Android process death — and the (big) implications for your app
Possible solutions:
Lazy loading/reactive approach. I try to use it as much as possible but there is always some code I need to run in a blocking way before user can interact with the app so this is not enough.
Putting all of that code in App.onCreate(). This would probably work for small apps but I've seen large apps that take 5-10 seconds to initialize, and I doubt they use onCreate() for that. Possible downsides: ANR and/or excessive startup time in Android Vitals?
Checking if the app is initialized in a BaseActivity, but that would require either blocking onCreate or managing lifecycle callbacks manually which doesn't sound like a good idea.
So, what's the proper way to run some code every time the app is launched?
Note: Normally StarterActivity would be a splash screen, AppLoader would be injected, etc, but I left that out for simplicity.

AndroidManifest.xml
<application
android:name=".AppLoader"
AppLoader.java
public class AppLoader extends Application {
private static Object someInstance;
#Override
public void onCreate() {
super.onCreate();
// DO YOUR STUFF
}
}
Update
- Use Handler with splash screen.
public class StarterActivity extends AppCompatActivity {
private Handler handler;
private Runnable myStuffRunnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
myStuffRunnable = new Runnable(){
public void run(){
// DO MY STUFF
MainActivity.start(this);
}
};
}
#Override
protected void onPause() {
handler.removeCallbacks(myStuffRunnable);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
handler.post(myStuffRunnable);
}
#Override
protected void onDestroy() {
handler.removeCallbacks(myStuffRunnable);
super.onDestroy();
}
}

Your app is throwing the RuntimeException you set in AppLoader.checkInitialized() method, because your someInstance object is losing it's state when the app goes to background and gets killed by the system ('cause you have set your device to hold zero background threads). So, when you try to reopen the app, the system launches MainActivity directly (and not StarterActivity) because it is trying to restore it's previous state. But variables are not restored, not even static variables.
So, if you need the Object someInstance on your MainActivity, you should integrate it's instantiation into MainActivitie's lifecycle, overriding methods like onSavedInstanceState, onRestoreInstanceState, etc, to properly handle and reaload this object if your app gets killed by the system.
Take a look on this https://developer.android.com/guide/components/activities/activity-lifecycle

If anyone's interested, I ended up just redirecting the user to StarterActivity if needed to make sure the necessary code is executed at every start.
public abstract class BaseActivity extends AppCompatActivity {
private boolean isCreated;
#Override
protected final void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!appLoader.isLoaded()) {
StarterActivity.start(this);
finish();
return;
}
onCreateActivity(savedInstanceState);
isCreated = true;
}
protected void onCreateActivity(#Nullable Bundle savedInstanceState) {
}
#Override
protected final void onDestroy() {
super.onDestroy();
if (isCreated) {
onDestroyActivity();
}
}
protected void onDestroyActivity() {
}
}
All activities extend BaseActivity (except StarterActivity) and override onCreateActivity/onDestroyActivity instead of onCreate/onDestroy.

Related

Force to launch SplashActivity onRestart another activity

I have an SplashActivity that create an ArrayList of custom CommerceObjects. This List will be used in the rest of the app, in diferent activities and fragments. The problem is that sometimes, when the app is stoped and then restarted, the objects List appear as not initialized. The solution is to check if the ArrayList is not null and in the case of being null force the SplashActivity launch again and remake the ArrayList. I tried to do this in the onRestart method in the rest of activities but is not working at all.
For example, this is the way that I'm checking in MainActivity if the ArrayList (created in SplashActivity) is null.
public class MainActivity extends AppCompatActivity {
...
#Override
protected void onRestart() {
// If the full list of commerces is null or is empty, launch the SplashActivity.
// Here check if the ArrayList of CommerceObjects is null
if (SplashActivity._commerces == null || SplashActivity._commerces.size() == 0) {
Intent mIntent = new Intent(MainActivity.this, SplashActivity.class);
startActivity(mIntent);
this.finish();
}
super.onRestart();
}
...
}
So, the array list to check is "_commerces". It's decalred as public static in SplashActivity. I need to check if is not null no mather what fragment or activity is currently in the front of the stack.
What I'm missing?
UPDATE
I recommend you to use onStart().
onRestart() is not called if App process is killed by Android OS.
https://developer.android.com/reference/android/app/Activity.html
ORIGINAL
The static variables will be initialized by Android OS.
see: static variable null when returning to the app
So I recommend you to avoid using static variables.
Make your Application class and Hold the CommerceObjects in your Application instance.
Following codes explains.
Make your Application class:
public class App extends Application {
private CommerceObjects mCommerces;
public void setCommerces(CommerceObjects commerces) {
mCommerces = commerces;
}
public CommerceObjects getCommerces() {
return mCommerces;
}
public static App get(Context context) {
return (App) context.getApplicationContext();
}
}
Set name of application in your AndroidManifest.xml:
<application
...
android:name=".App">
...
</application>
Initialize commerces in your SplashActivity:
public class SplashActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
initializeCommerces();
}
private void initializeCommerces() {
//do initialize tasks
...
CommerceObjects commerces = ...;
//set CommerceObjects to App
App.get(this).setCommerces(commerces);
//start other Activity. ex) MainActivity
}
}
Use commerces in anther Activity:
public class MainActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//use CommerceObjects
CommerceObjects commerces = App.get(this).getCommerces();
...
}
}

Activity onResume( ) called when changing apps

I would like to know if there's a way to differentiate when the onResume() method of an activity is called from the same app or a different application.
For example I would like to differentiate when my main activity's onResume() is called when I return to the app from Whatsapp or another activity of my app.
I know there's a way to do it with GET_TASKS permission but that method is deprecated and not recommended.
Thank you
It appears you want to know when app comes from the background to foreground in each Activity. This can be achieved using a class that extends the Application class and implements the ActivityLifecycleCallbacks interface. Firstly, here's the code for this class:
public class MyApplication extends Application implements ActivityLifecycleCallbacks {
public boolean appInBackground;
private Handler mHandler;
...
#Override
public void onActivityResumed(Activity activity) {
Log.i("Activity Resumed", activity.getLocalClassName());
mHandler.cancelCallbacksAndMessages(null);
appInBackground = false;
}
#Override
public void onActivityPaused(Activity activity) {
Log.i("Activity Paused", activity.getLocalClassName());
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
appInBackground = true;
}
}, 5000);
}
...
}
If you notice in above code we are basically giving the app a grace period of 5 seconds to switch from one activity to other. If it exceeds more than that, it means the app was in background. The above class will need to registered in the <application> tag of your manifest file under android:name:"" property as android:name:"MyApplication".
To use this in your activity, override the onPause():
private boolean resumedFromBg;
#Override
protected void onPause() {
super.onPause();
resumedFromBg = ((MyApplication) getApplication()).appInBackground;
}
Let me know if you run into any issues~

Android return to app call method

I just recently started learning how to build android apps, and encountered a problem:
I want, when users leave the app (go to the homescreen, multitask), and they return, that the app calls a certain method. How can I do that?
This problem is more tricky than it may look like. When you return to app after leaving it, then is called method onResume of activity which was active when app was interrupted. But same happens when you go from one activity to another (onResume of second activity is called). If you just call method from onResume, it will be called every time onResume of any activity is called.
Take a look at this solution...
First, you have BaseActivity which is extended by all activities that need to call that method:
abstract public class BaseActivity extends Activity implements IName {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
if (AppClass.getPausedActivity() != null) {
if (this.getClassName().equals(AppClass.getPausedActivity()))
//call specific method
}
AppClass.setPausedActivity("");
super.onResume();
}
#Override
protected void onPause() {
AppClass.setPausedActivity(this.getClassName());
super.onPause();
}
#Override
abstract public String getClassName();
}
As you can see it implements interface IName:
public interface IName
{
String getClassName();
}
BaseActivity in onPause (when it is interrupted) calls setPausedActivity method of AppClass which remembers last activity name that was interrupted. In onResume (when app and activity is continued) we compare name of current activity and last paused activity.
So, when app is interrupted, these names will be same because you paused one activity and you got back to the same one. When you call activity from some other activity these names will not be same and method will not be called.
Here is code for AppClass:
public class AppClass extends Application {
public static String pausedActivity;
public static String getPausedActivity() {
return pausedActivity;
}
public static void setPausedActivity(String _pausedActivity) {
pausedActivity = _pausedActivity;
}
}
Also, here is example of activity that extends BaseActivity:
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
}
//here you set name of current activity
#Override
public String getClassName() {
return "MainActivity";
}
}
You are bound to the Activity lifecycle. You will need to implement corresponding logic to figure out if the user has been in your app before (i.e. using SharedPreferences).

Keep record of launched activities in Android

I was wondering how to keep a record of launched activites for logging purposes. what broadcast receiver I have to subscribe to intercept this intent? or what intent-filter to use? I figure that I must use some type of long-running service in the background.
My first objetive is to track main-focus applications, some sort of history.
Want to get finally some similar to:
- Launched app com.android.xxx
- Launched app xx.yy.zz
- App xx.yy.zz lost focus
Thanks in advance
EDIT - Just see that app MyAppRank , that does exactly what i mean
What i'm able to figure out from your question is that you want to keep track of all the activities when they are launched in your application. If that is correct, the solution may work for you:
Crate a BaseActivity which all of your Activities should extend
public class BaseActivity extends Activity
{
private Activity activity;
public static final String INTENTFILTER_TRACK_MY_ACTIVITIES="INTENTFILTER_TRACK_MY_ACTIVITIES";
public static final String INTENTFILTER_REMOVE_MY_ACTIVITIES="INTENTFILTER_REMOVE_MY_ACTIVITIES";
public void setActivity(Activity act)
{
activity = act;
}
public Activity getActivity()
{
return activity;
}
#Override protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Intent intent = new Intent();
intent.setAction(INTENTFILTER_TRACK_MY_ACTIVITIES);
intent.putExtra("activityName", activity.getClass().getSimpleName());
sendBroadcast(intent);
}
#Override protected void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
Intent intent = new Intent();
intent.setAction(INTENTFILTER_REMOVE_MY_ACTIVITIES);
intent.putExtra("activityName", activity.getClass().getSimpleName());
sendBroadcast(intent);
setActivity(null);
}
}
Now extend above BaseActivity for all your activities. i.e instead of extending your Activities should extend BaseActivity and call setActivity(this); in onCreate like below:
public class MyActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setActivity(this);
//write your other code form here
}
}
3.Then write a BroadcastReceiver like below:
class TrackActivitiesReceiver extends BroadcastReceiver
{
private static final Object SEPERATOR = ",";// use , as seperator
String sb="";
#Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equalsIgnoreCase(BaseActivity.INTENTFILTER_TRACK_MY_ACTIVITIES))
{
sb+=intent.getStringExtra("activityName");
sb+=SEPERATOR;
}
else if(intent.getAction().equalsIgnoreCase(BaseActivity.INTENTFILTER_REMOVE_MY_ACTIVITIES))
{
sb=sb.replace(intent.getStringExtra("activityName")+SEPERATOR, "");
}
}}
4Finally, Register above Receiver in your AndroidManifest.xml
<receiver
android:name="TrackActivitiesReceiver"
android:exported="false" >
<intent-filter>
<action android:name="INTENTFILTER_TRACK_MY_ACTIVITIES" />
</intent-filter>
</receiver>
Hope this solves your problem. cheers!
There are no Intents broadcast when applications are started or when applications come to the foreground. There isn't anything that you can hook into as a listener to get these events.
The way you can do this (which is the way apps like MyAppRank do it) is to use the methods of the ActivityManager:
getRunningTasks()
getRunningAppProcesses()
getRecentTasks()
You create a Service which runs all the time and at regular intervals calls methods of the ActvityManager to determine which task is in the foreground and you can "infer" what the user has done (or is doing). It isn't an exact science.
Note: You will need android.permission.GET_TASKS and none of this works anymore as of API 21 (Android 5, Lollipop). As of API 21 the security has been tightened and an application can only get information about its own tasks, not other tasks in the system.

Checking if an Android application is running in the background

By background, I mean none of the application's activities are currently visible to the user?
There are few ways to detect whether your application is running in the background, but only one of them is completely reliable:
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();
}
Update
ActivityLifecycleCallbacks were added in API level 14 (Android 4.0). You can use them to track whether an activity of your application is currently visible to the user. Check Cornstalks' answer below for the details.
The wrong one
I used to suggest the following solution:
You can detect currently foreground/background application with ActivityManager.getRunningAppProcesses() which returns a list of RunningAppProcessInfo records. To determine if your application is on the foreground check RunningAppProcessInfo.importance field for equality to RunningAppProcessInfo.IMPORTANCE_FOREGROUND while RunningAppProcessInfo.processName is equal to your application package name.
Also if you call ActivityManager.getRunningAppProcesses() from your application UI thread it will return importance IMPORTANCE_FOREGROUND for your task no matter whether it is actually in the foreground or not. Call it in the background thread (for example via AsyncTask) and it will return correct results.
While this solution may work (and it indeed works most of the time) I strongly recommend to refrain from using it. And here's why. As Dianne Hackborn wrote:
These APIs are not there for applications to base their UI flow on, but to do things like show the user the running apps, or a task manager, or such.
Yes there is a list kept in memory for these things. However, it is off in another process, managed by threads running separately from yours, and not something you can count on (a) seeing in time to make the correct decision or (b) have a consistent picture by the time you return. Plus the decision about what the "next" activity to go to is always done at the point where the switch is to happen, and it is not until that exact point (where the activity state is briefly locked down to do the switch) that we actually know for sure what the next thing will be.
And the implementation and global behavior here is not guaranteed to remain the same in the future.
I wish I had read this before I posted an answer on the SO, but hopefully it's not too late to admit my error.
Another wrong solution
Droid-Fu library mentioned in one of the answers uses ActivityManager.getRunningTasks for its isApplicationBroughtToBackground method. See Dianne's comment above and don't use that method either.
GOOGLE SOLUTION - not a hack, like previous solutions. Use ProcessLifecycleOwnerKotlin:
class ArchLifecycleApp : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
//App in background
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
// App in foreground
}
}
Java:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
#Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
}
}
in app.gradle
dependencies {
...
implementation "android.arch.lifecycle:extensions:1.1.0"
//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
}
allprojects {
repositories {
...
google()
jcenter()
maven { url 'https://maven.google.com' }
}
}
You can read more about Lifecycle related architecture components here - https://developer.android.com/topic/libraries/architecture/lifecycle
DO NOT USE THIS ANSWER
user1269737's answer is the proper (Google/Android approved) way to do this. Go read their answer and give them a +1.
I'll leave my original answer here for posterity's sake. This was the best available back in 2012, but now Android has proper support for this.
Original answer
The key is using ActivityLifecycleCallbacks (note that this requires Android API level 14 (Android 4.0)). Just check if the number of stopped activities is equal to the number of started activities. If they're equal, your application is being backgrounded. If there are more started activities, your application is still visible. If there are more resumed than paused activities, your application is not only visible, but it's also in the foreground. There are 3 main states that your activity can be in, then: visible and in the foreground, visible but not in the foreground, and not visible and not in the foreground (i.e. in the background).
The really nice thing about this method is that it doesn't have the asynchronous issues getRunningTasks() does, but you also don't have to modify every Activity in your application to set/unset something in onResumed()/onPaused(). It's just a few lines of code that's self contained, and it works throughout your whole application. Plus, there are no funky permissions required either.
MyLifecycleHandler.java:
public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
// I use four separate variables here. You can, of course, just use two and
// increment/decrement them instead of using four and incrementing them all.
private int resumed;
private int paused;
private int started;
private int stopped;
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
++resumed;
}
#Override
public void onActivityPaused(Activity activity) {
++paused;
android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityStarted(Activity activity) {
++started;
}
#Override
public void onActivityStopped(Activity activity) {
++stopped;
android.util.Log.w("test", "application is visible: " + (started > stopped));
}
// If you want a static function you can use to check if your application is
// foreground/background, you can use the following:
/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/
}
MyApplication.java:
// Don't forget to add it to your manifest by doing
// <application android:name="your.package.MyApplication" ...
public class MyApplication extends Application {
#Override
public void onCreate() {
// Simply add the handler, and that's it! No need to add any code
// to every activity. Everything is contained in MyLifecycleHandler
// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(new MyLifecycleHandler());
}
}
#Mewzer has asked some good questions about this method that I'd like to respond to in this answer for everyone:
onStop() is not called in low memory situations; is that a problem here?
No. The docs for onStop() say:
Note that this method may never be called, in low memory situations where the system does not have enough memory to keep your activity's process running after its onPause() method is called.
The key here is "keep your activity's process running..." If this low memory situation is ever reached, your process is actually killed (not just your activity). This means that this method of checking for backgrounded-ness is still valid because a) you can't check for backgrounding anyway if your process is killed, and b) if your process starts again (because a new activity is created), the member variables (whether static or not) for MyLifecycleHandler will be reset to 0.
Does this work for configuration changes?
By default, no. You have to explicitly set configChanges=orientation|screensize (| with anything else you want) in your manifest file and handle the configuration changes, or else your activity will be destroyed and recreated. If you do not set this, your activity's methods will be called in this order: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume. As you can see, there is no overlap (normally, two activities overlap very briefly when switching between the two, which is how this backgrounding-detection method works). In order to get around this, you must set configChanges so that your activity is not destroyed. Fortunately, I've had to set configChanges already in all of my projects because it was undesirable for my entire activity to get destroyed on screen rotate/resize, so I've never found this to be problematic. (thanks to dpimka for refreshing my memory on this and correcting me!)
One note:
When I've said "background" here in this answer, I've meant "your app is no longer visible." Android activities can be visible yet not in the foreground (for example, if there's a transparent notification overlay). That's why I've updated this answer to reflect that.
It's important to know that Android has a weird limbo moment when switching activities where nothing is in the foreground. For this reason, if you check if your application is in the foreground when switching between activities (in the same app), you'll be told you're not in the foreground (even though your app is still the active app and is visible).
You can check if your app is in the foreground in your Activity's onPause() method after super.onPause(). Just remember the weird limbo state I just talked about.
You can check if your app is visible (i.e. if it's not in the background) in your Activity's onStop() method after super.onStop().
Starting support library version 26 you can use ProcessLifecycleOwner, just add it to your dependency like described here, for example:
dependencies {
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
}
And then just query ProcessLifecycleOwner whenever you want for app state, examples:
// Check if app is in background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;
// Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
Since Android API 16 there is a simple way to check if app is in foreground. It may not be foolproof, but no methods on Android are foolproof. This method is good enough to use when your service receives update from server and has to decide whether to show notification, or not (because if UI is foreground, user will notice the update without notification).
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Idolon's answer is error prone and much more complicated althought repeatead here check android application is in foreground or not? and here Determining the current foreground application from a background task or service
There is a much more simpler approach:
On a BaseActivity that all Activities extend:
protected static boolean isVisible = false;
#Override
public void onResume()
{
super.onResume();
setVisible(true);
}
#Override
public void onPause()
{
super.onPause();
setVisible(false);
}
Whenever you need to check if any of your application activities is in foreground just check isVisible();
To understand this approach check this answer of side-by-side activity lifecycle: Activity side-by-side lifecycle
I tried the recommended solution that uses Application.ActivityLifecycleCallbacks and many others, but they didn't work as expected. Thanks to Sarge, I came up with a pretty easy and straightforward solution that I am describing below.
They key of the solution is the fact of understanding that if we have ActivityA and ActivityB, and we call ActivityB from ActivityA (and not call ActivityA.finish), then ActivityB's onStart() will be called before ActivityA onStop().
That's also the main difference between onStop() and onPause() that none did mention in the articles I read.
So based on this Activity's Lifecycle behavior, you can simply count how many times did onStart() and onPause() got called in your program. Note that for each Activity of your program, you must override onStart() and onStop(), in order to increment/decrement the static variable used for counting. Below is the code implementing this logic. Note that I am using a class that extends Application, so dont forget to declare on Manifest.xml inside Application tag: android:name=".Utilities", although it can be implemented using a simple custom class too.
public class Utilities extends Application
{
private static int stateCounter;
public void onCreate()
{
super.onCreate();
stateCounter = 0;
}
/**
* #return true if application is on background
* */
public static boolean isApplicationOnBackground()
{
return stateCounter == 0;
}
//to be called on each Activity onStart()
public static void activityStarted()
{
stateCounter++;
}
//to be called on each Activity onStop()
public static void activityStopped()
{
stateCounter--;
}
}
Now on each Activity of our program, we should override onStart() and onStop() and increment/decrement as shown below:
#Override
public void onStart()
{
super.onStart();
Utilities.activityStarted();
}
#Override
public void onStop()
{
Utilities.activityStopped();
if(Utilities.isApplicationOnBackground())
{
//you should want to check here if your application is on background
}
super.onStop();
}
With this logic, there are 2 possible cases:
stateCounter = 0 : The number of stopped is equal with the number of started Activities, which means that the application is running on the background.
stateCounter > 0 : The number of started is bigger than the number of stopped, which means that the application is running on the foreground.
Notice: stateCounter < 0 would mean that there are more stopped Activities rather than started, which is impossible. If you encounter this case, then it means that you are not increasing/decreasing the counter as you should.
You are ready to go. You should want to check if your application is on background inside onStop().
There is no way, short of you tracking it yourself, to determine if any of your activities are visible or not. Perhaps you should consider asking a new StackOverflow question, explaining what it is you are trying to achieve from a user experience, so we can perhaps give you alternative implementation ideas.
You can use ComponentCallbacks2 to detect if the app is in background. BTW this callback is only available in API Level 14 (Ice Cream Sandwich) and above.
You will get a call to the method:
public abstract void onTrimMemory (int level)
if the level is ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN then the app is in background.
You can implement this interface to an activity, service, etc.
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
#Override
public void onConfigurationChanged(final Configuration newConfig) {
}
#Override
public void onLowMemory() {
}
#Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// app is in background
}
}
}
Building on #Cornstalks answer to include a couple of useful features.
Extra features:
introduced singleton pattern so you can do this anywhere in the application: AppLifecycleHandler.isApplicationVisible() and AppLifecycleHandler.isApplicationInForeground()
added handling of duplicate events (see comments // take some action on change of visibility and // take some action on change of in foreground)
App.java
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
}
}
AppLifecycleHandler.java
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
private int resumed;
private int started;
private final String DebugName = "AppLifecycleHandler";
private boolean isVisible = false;
private boolean isInForeground = false;
private static AppLifecycleHandler instance;
public static AppLifecycleHandler getInstance() {
if (instance == null) {
instance = new AppLifecycleHandler();
}
return instance;
}
private AppLifecycleHandler() {
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
++resumed;
android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
#Override
public void onActivityPaused(Activity activity) {
--resumed;
android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityStarted(Activity activity) {
++started;
android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
#Override
public void onActivityStopped(Activity activity) {
--started;
android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
private void setVisible(boolean visible) {
if (isVisible == visible) {
// no change
return;
}
// visibility changed
isVisible = visible;
android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);
// take some action on change of visibility
}
private void setForeground(boolean inForeground) {
if (isInForeground == inForeground) {
// no change
return;
}
// in foreground changed
isInForeground = inForeground;
android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);
// take some action on change of in foreground
}
public static boolean isApplicationVisible() {
return AppLifecycleHandler.getInstance().started > 0;
}
public static boolean isApplicationInForeground() {
return AppLifecycleHandler.getInstance().resumed > 0;
}
}
The best solution I have come up with uses timers.
You have start a timer in onPause() and cancel the same timer in onResume(), there is 1 instance of the Timer (usually defined in the Application class). The timer itself is set to run a Runnable after 2 seconds (or whatever interval you think is appropriate), when the timer fires you set a flag marking the application as being in the background.
In the onResume() method before you cancel the timer, you can query the background flag to perform any startup operations (e.g. start downloads or enable location services).
This solution allows you to have several activities on the back stack, and doesn't require any permissions to implement.
This solution works well if you use an event bus too, as your timer can simply fire an event and various parts of your app can respond accordingly.
If you turn on developer settings "Don't keep actvities" - check only count of created activites is not enough. You must check also isSaveInstanceState. My custom method isApplicationRunning() check is android app is running:
Here my work code:
public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
private int created;
private boolean isSaveInstanceState;
private static AppLifecycleService instance;
private final static String TAG = AppLifecycleService.class.getName();
public static AppLifecycleService getInstance() {
if (instance == null) {
instance = new AppLifecycleService();
}
return instance;
}
public static boolean isApplicationRunning() {
boolean isApplicationRunning = true;
if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
isApplicationRunning = false;
}
return isApplicationRunning;
}
public static boolean isSaveInstanceState() {
return AppLifecycleService.getInstance().isSaveInstanceState;
}
public static int getCountCreatedActvities() {
return AppLifecycleService.getInstance().created;
}
private AppLifecycleService() {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
this.isSaveInstanceState = true;
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
++created;
}
#Override
public void onActivityDestroyed(Activity activity) {
--created;
}
#Override
public void onActivityResumed(Activity activity) { }
#Override
public void onActivityPaused(Activity activity) { }
#Override
public void onActivityStarted(Activity activity) { }
#Override
public void onActivityStopped(Activity activity) { }
}
To piggyback on what CommonsWare and Key have said, you could perhaps extend the Application class and have all of your activities call that on their onPause/onResume methods. This would allow you to know which Activity(ies) are visible, but this could probably be handled better.
Can you elaborate on what you have in mind exactly? When you say running in the background do you mean simply having your application still in memory even though it is not currently on screen? Have you looked into using Services as a more persistent way to manage your app when it is not in focus?
I did my own implementation of ActivityLifecycleCallbacks. I'm using SherlockActivity, but for normal Activity class might work.
First, I'm creating an interface that have all methods for track the activities lifecycle:
public interface ActivityLifecycleCallbacks{
public void onActivityStopped(Activity activity);
public void onActivityStarted(Activity activity);
public void onActivitySaveInstanceState(Activity activity, Bundle outState);
public void onActivityResumed(Activity activity);
public void onActivityPaused(Activity activity);
public void onActivityDestroyed(Activity activity);
public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}
Second, I implemented this interface in my Application's class:
public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
#Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
#Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
#Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
#Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
Third, I'm creating a class that extends from SherlockActivity:
public class MySherlockActivity extends SherlockActivity {
protected MyApplication nMyApplication;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nMyApplication = (MyApplication) getApplication();
nMyApplication.onActivityCreated(this, savedInstanceState);
}
protected void onResume() {
// TODO Auto-generated method stub
nMyApplication.onActivityResumed(this);
super.onResume();
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
nMyApplication.onActivityPaused(this);
super.onPause();
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
nMyApplication.onActivityDestroyed(this);
super.onDestroy();
}
#Override
protected void onStart() {
nMyApplication.onActivityStarted(this);
super.onStart();
}
#Override
protected void onStop() {
nMyApplication.onActivityStopped(this);
super.onStop();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
nMyApplication.onActivitySaveInstanceState(this, outState);
super.onSaveInstanceState(outState);
}
}
Fourth, all class that extend from SherlockActivity, I replaced for MySherlockActivity:
public class MainActivity extends MySherlockActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Now, in the logcat you will see the logs programmed in the Interface implementation made in MyApplication.
Offical docs:
The system distinguishes between foreground and background apps. (The definition of background for purposes of service limitations is distinct from the definition used by memory management; an app might be in the background as pertains to memory management, but in the foreground as pertains to its ability to launch services.) An app is considered to be in the foreground if any of the following is true:
It has a visible activity, whether the activity is started or paused.
It has a foreground service.
Another foreground app is connected to the app, either by binding to one of its services or by making use of one of its content providers. For example, the app is in the foreground if another app binds to its:
IME
Wallpaper service
Notification listener
Voice or text service
If none of those conditions is true, the app is considered to be in the background.
The only one correct solution:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
MyApp.mainActivity = this;
super.onCreate(savedInstanceState);
...
}
MyApp.java:
public class MyApp extends Application implements LifecycleObserver {
public static MainActivity mainActivity = null;
#Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onAppBackgrounded() {
// app in background
if (mainActivity != null) {
...
}
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
void onAppForegrounded() {
// app in foreground
if (mainActivity != null) {
...
}
}
}
No any solution work for me, however I propose a raw solution. This should work. If isAppBackground return false, then app must be in foreground.
public static boolean isAppBackground(Context context){
boolean isBackground=true;
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH){
List<ActivityManager.RunningAppProcessInfo> runningProcesses =activityManager.getRunningAppProcesses();
for(ActivityManager.RunningAppProcessInfo processInfo:runningProcesses){
if(processInfo.importance==ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
for(String activeProcess:processInfo.pkgList){
if(activeProcess.equals(context.getPackageName())){
isBackground = false;
}
}
}
}
}else{
List<ActivityManager.RunningTaskInfo> taskInfo = activityManager.getRunningTasks(1);
if(taskInfo.size()>0) {
ComponentName componentName = taskInfo.get(0).topActivity;
if(componentName.getPackageName().equals(context.getPackageName())){
isBackground = false;
}
}
}
return isBackground;
}
Activity gets paused when a Dialog comes above it so all the recommended solutions are half-solutions. You need to create hooks for dialogs as well.
I recommend reading through this page: http://developer.android.com/reference/android/app/Activity.html
In short, your activity is no longer visible after onStop() has been called.
Since it isn't already mentioned, I will suggest the readers to explore ProcessLifecycleOwner available through Android Architecture components
This code will check foreground and background in any condition:
Java Code:
private static boolean isApplicationForeground(Context context) {
KeyguardManager keyguardManager =
(KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardManager.isKeyguardLocked()) {
return false;
}
int myPid = Process.myPid();
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> list;
if ((list = activityManager.getRunningAppProcesses()) != null) {
for (ActivityManager.RunningAppProcessInfo aList : list) {
ActivityManager.RunningAppProcessInfo info;
if ((info = aList).pid == myPid) {
return info.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
}
}
}
return false;
}
Kotlin Code:
private fun isApplicationForeground(context: Context): Boolean {
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (keyguardManager.isKeyguardLocked) {
return false
}
val myPid = Process.myPid()
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
var list: List<ActivityManager.RunningAppProcessInfo>
if (activityManager.runningAppProcesses.also { list = it } != null) {
for (aList in list) {
var info: ActivityManager.RunningAppProcessInfo
if (aList.also { info = it }.pid == myPid) {
return info.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
}
}
}
return false
}
Simple and straight-forward answer:
override fun onPause() {
Log.i("APP LIFECYCLE", "App Enter BACKground")
isForeground = false
super.onPause()
}
override fun onResume() {
Log.i("APP LIFECYCLE", "App Enter FOREground")
isForeground = true
super.onResume()
}
Then just use the isForeground property of your activity to check the status.
Another solution for this old post (for those that it might help) :
<application android:name=".BaseApplication" ... >
public class BaseApplication extends Application {
private class Status {
public boolean isVisible = true;
public boolean isFocused = true;
}
private Map<Activity, Status> activities;
#Override
public void onCreate() {
activities = new HashMap<Activity, Status>();
super.onCreate();
}
private boolean hasVisibleActivity() {
for (Status status : activities.values())
if (status.isVisible)
return true;
return false;
}
private boolean hasFocusedActivity() {
for (Status status : activities.values())
if (status.isFocused)
return true;
return false;
}
public void onActivityCreate(Activity activity, boolean isStarting) {
if (isStarting && activities.isEmpty())
onApplicationStart();
activities.put(activity, new Status());
}
public void onActivityStart(Activity activity) {
if (!hasVisibleActivity() && !hasFocusedActivity())
onApplicationForeground();
activities.get(activity).isVisible = true;
}
public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
activities.get(activity).isFocused = hasFocus;
}
public void onActivityStop(Activity activity, boolean isFinishing) {
activities.get(activity).isVisible = false;
if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
onApplicationBackground();
}
public void onActivityDestroy(Activity activity, boolean isFinishing) {
activities.remove(activity);
if(isFinishing && activities.isEmpty())
onApplicationStop();
}
private void onApplicationStart() {Log.i(null, "Start");}
private void onApplicationBackground() {Log.i(null, "Background");}
private void onApplicationForeground() {Log.i(null, "Foreground");}
private void onApplicationStop() {Log.i(null, "Stop");}
}
public class MyActivity extends BaseActivity {...}
public class BaseActivity extends Activity {
private BaseApplication application;
#Override
protected void onCreate(Bundle state) {
application = (BaseApplication) getApplication();
application.onActivityCreate(this, state == null);
super.onCreate(state);
}
#Override
protected void onStart() {
application.onActivityStart(this);
super.onStart();
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
application.onActivityWindowFocusChanged(this, hasFocus);
super.onWindowFocusChanged(hasFocus);
}
#Override
protected void onStop() {
application.onActivityStop(this, isFinishing());
super.onStop();
}
#Override
protected void onDestroy() {
application.onActivityDestroy(this, isFinishing());
super.onDestroy();
}
}
See the comment in the onActivityDestroyed function.
Works with SDK target version 14> :
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
public static int active = 0;
#Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
active--;
}
#Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
active++;
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
#Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
active++;
}
#Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
active--;
}
#Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
active--;
// if active var here ever becomes zero, the app is closed or in background
if(active == 0){
...
}
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
active++;
}
}
You should use a shared preference to store the property and act upon it using service binding from your activities. If you use binding only, (that is never use startService), then your service would run only when you bind to it, (bind onResume and unbind onPause) that would make it run on foreground only, and if you do want to work on background you can use the regular start stop service.
I think this question should be more clear. When? Where? What is your specific situation you want to konw if your app is in background?
I just introduce my solution in my way.
I get this done by using the field "importance" of RunningAppProcessInfo class in every activity's onStop method in my app, which can be simply achieved by providing a BaseActivity for other activities to extend which implements the onStop method to check the value of "importance". Here is the code:
public static boolean isAppRunning(Context context) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
return true;
}
}
}
return false;
}
What about using getApplicationState().isInForeground() ?
In my opinion, many answers introduce a heavy load of code and bring lots of complexity and non-readability.
When people ask on SO how to communicate between a Service and a Activity, I usually advice to use the LocalBroadcastManager.
Why?
Well, by quoting the docs:
You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.
It is more efficient than sending a global broadcast through the system.
Not in the the docs:
It does not require external libraries
The code is minimal
It's fast to implement and understand
No custom self-implemented callbacks / ultra-singleton / intra-process
pattern whatsoever...
No strong references on Activity, Application, ...
Description
So, you want to check if any of the Activity is currently in the foreground. You usually do that in a Service, or your Application class.
This means, your Activity objects become the sender of a signal (I'm on / I'm off). Your Service, on the other hand, becomes the Receiver.
There are two moments in which your Activity tells you if it's going in the foreground or in the background (yes only two... not 6).
When the Activity goes into the foreground, the onResume() method is triggered (also called after onCreate()).
When the Activity goes in the back, onPause() is called.
These are the moments in which your Activity should send the signal to your Service to describe its state.
In case of multiple Activity's, remember the an Activity goes into the background first, then another one comes into the foreground.
So the situation would be:*
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
The Service / Application will simply keep listening for those signals and act accordingly.
Code (TLDR)
Your Service must implement a BroadcastReceiver in order to listen for signals.
this.localBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// received data if Activity is on / off
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
Register the Receiver in Service::onCreate()
#Override
protected void onCreate() {
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
Un-register it in Service::onDestroy()
#Override
protected void onDestroy() {
// I'm dead, no need to listen to anything anymore.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
Now your Activity's must communicated their state.
In Activity::onResume()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
In Activity::onPause()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
A very, very common situation
Developer: I want to send data from my Service and update the Activity. How do I check if the Activity is in the foreground?
There is usually no need to check if the Activity is in the foreground or not. Just send the data via LocalBroadcastManager from your Service. If the Activity is on, then it will respond and act.
For this very common situation, the Service becomes the sender, and the Activity implements the BroadcastReceiver.
So, create a Receiver in your Activity. Register it in onResume() and un-register it in onPause(). There is no need to use the other life-cycle methods.
Define the Receiver behavior in onReceive() (update ListView, do this, do that, ...).
This way the Activity will listen only if it's in the foreground and nothing will happen if it's in the back or is destroyed.
In case of multiple Activity's, whichever Activity is on will respond (if they also implement the Receiver).
If all are in the background, nobody will respond and the signal will simply get lost.
Send the data from the Service via Intent (see code above) by specifying the signal ID.
Except for Multi-Window Support. It may be tricky (please test it if needed)...
fun isAppInForeground(): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager ?: return false
val appProcesses = activityManager.runningAppProcesses ?: return false
val packageName = packageName
for (appProcess in appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName) {
return true
}
}
return false
}
None of the answers quite fitted the specific case if you're looked to know if a specfic activity is in the forground and if you're an SDK without direct access to the Application. For me I was in background thread having just recieved a push notification for a new chat message and only want to display a system notification if the chat screen isn't in the foreground.
Using the ActivityLifecycleCallbacks that as been recommended in other answers I've created a small util class that houses the logic to whether MyActivity is in the Foreground or not.
class MyActivityMonitor(context: Context) : Application.ActivityLifecycleCallbacks {
private var isMyActivityInForeground = false
init {
(context.applicationContext as Application).registerActivityLifecycleCallbacks(this)
}
fun isMyActivityForeground() = isMyActivityInForeground
override fun onActivityPaused(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = false
}
}
override fun onActivityResumed(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = true
}
}
}

Categories

Resources