By background, I mean none of the application\'s activities are currently visible to the user?
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:
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 theActivity
. How do I check if theActivity
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.
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
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?
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.
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) { }
}
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();
}
}