By background, I mean none of the application's activities are currently visible to the user?
相关问题
- How can I create this custom Bottom Navigation on
- Bottom Navigation View gets Shrink Down
- How to make that the snackbar action button be sho
- Listening to outgoing sms not working android
- How to create Circular view on android wear?
相关文章
- android开发 怎么把图片放入drawable的文件夹下
- android上如何获取/storage/emulated/下的文件列表
- androidStudio有个箭头不认识
- SQLite不能创建表
- Windows - Android SDK manager not listing any plat
- Animate Recycler View grid when number of columns
- Why is the app closing suddenly without showing an
- Android OverlayItem.setMarker(): Change the marker
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).
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.
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 aActivity
, I usually advice to use the LocalBroadcastManager.Why?
Well, by quoting the docs:
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 aService
, or yourApplication
class.This means, your
Activity
objects become the sender of a signal (I'm on / I'm off). YourService
, on the other hand, becomes theReceiver
.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, theonResume()
method is triggered (also called afteronCreate()
).When the
Activity
goes in the back,onPause()
is called.These are the moments in which your
Activity
should send the signal to yourService
to describe its state.In case of multiple
Activity
's, remember the anActivity
goes into the background first, then another one comes into the foreground.So the situation would be:*
The
Service
/Application
will simply keep listening for those signals and act accordingly.Code (TLDR)
Your
Service
must implement aBroadcastReceiver
in order to listen for signals.Register the
Receiver
inService::onCreate()
Un-register it in
Service::onDestroy()
Now your
Activity
's must communicated their state.In
Activity::onResume()
In
Activity::onPause()
A very, very common situation
There is usually no need to check if the
Activity
is in the foreground or not. Just send the data viaLocalBroadcastManager
from yourService
. If theActivity
is on, then it will respond and act.For this very common situation, the
Service
becomes the sender, and theActivity
implements theBroadcastReceiver
.So, create a
Receiver
in yourActivity
. Register it inonResume()
and un-register it inonPause()
. There is no need to use the other life-cycle methods.Define the
Receiver
behavior inonReceive()
(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, whicheverActivity
is on will respond (if they also implement theReceiver
).If all are in the background, nobody will respond and the signal will simply get lost.
Send the data from the
Service
viaIntent
(see code above) by specifying the signal ID.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 everyActivity
in your application to set/unset something inonResumed()
/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:
MyApplication.java:
@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: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 to0
.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 setconfigChanges
so that your activity is not destroyed. Fortunately, I've had to setconfigChanges
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
'sonPause()
method aftersuper.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
'sonStop()
method aftersuper.onStop()
.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.
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:
Second, I implemented this interface in my Application's class:
Third, I'm creating a class that extends from SherlockActivity:
Fourth, all class that extend from SherlockActivity, I replaced for MySherlockActivity:
Now, in the logcat you will see the logs programmed in the Interface implementation made in MyApplication.