how to detect app is now foreground after minimizing the app? - android

by using onResume() i can check if an activity is foreground or not. My problem is this onResume() is fire each time even if i come from another activity to this activity.
So my main problem is ,if i minimizing the app by home button I want execute some code in each activity when app is come foreground BUT not using onResume().
I found an answer like this How to know in BroadcastReceiver if App is running on foreground? but i dont know how to register this receiver in android menifest to get the trigger when app is visible.
Please give me some tips how can i overcome this solution or code snippet which can help me. Thanks in advance :)

One thing to do what you want is to count the number of times onStart/onStop is called in your application. This will help you determine if you transitioned to your activity from inside or outside your application.
You must extend Application then create/register ActivityLifecycleCallbacks within that class. Also, make sure to specify the new Application class you created in the AndroidManifest.
Now, the trick is to keep a count variable in onActivityStarted/onActivityStopped to determine whether your Activity was navigated to from inside or outside the application.
Say you have 2 Activities in your app: FirstActivity & SecondActivity.
If you navigate from FirstActivity to SecondActivity the lifecycle calls will happen in this order: FirstActivity.onStart() > SecondActivity.onStart(), resulting in a count of 1.
If you navigate from outside your application, you will only see FirstActivity.onStart(), so the count is 0. This is all assuming you check the count after super.onStart() is called.
So, by checking count against 0/1 you can tell if your activity was launched from within the application or outside the application.
/**
* Extending the application class lets you use ActivityLifecycleCallbacks to
* keep track of all lifecycle callbacks in your application.
*/
public class MyApplication extends Application implements ActivityLifecycleCallbacks {
private int count = 0;
//Register activity lifecycle callbacks in onCreate
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
void onActivityStarted(Activity activity) {
count++;
}
void onActivityStopped(Activity activity) {
count--;
}
/**
* Use this method in your Activities to test if the activity was
* transitioned to from outside the application.
*
* If you call this method in Activity.onResume(), then count should be
* compared to 0. If you call this method in Activity.onStart() but
* *before* calling super.onStart(), then count should be compared to 0.
*
* However, if you call this method after super.onStart(), then count
* should be compared to 1.
*/
public boolean cameFromOutsideApplication() {
return count == 0;
}
//Don't need to use the rest of the activity lifecycle callbacks
void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
void onActivityDestroyed(Activity activity) {
}
void onActivityPaused(Activity activity) {
}
void onActivityResumed(Activity activity) {
}
void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
}
You may gain some more information here as well but it does not use ActivityLifecycleCallbacks which is easier to use.

If you want to register your receiver you can use the following code,
<receiver
android:name="com.package.name.ReceiverClassName"
android:enabled="true" >
</receiver>

Related

Android - How to know when app has been resumed after being in background

I'm trying to determine when my app is being resumed after the user closed it, in any way, pressing home button, back button or switching to another app.
What I need to do is to set a boolean when the app goes in background, so, when it is resumed, I know that it was in background before and I can act accordingly.
I tried to use onResume and onPause methods in activities to know when the app goes in background and it is then resumed, but as only one activity can be alive at at time, I had no success. When an activity is paused, this doesn't mean that the app went to background, because another activity could have been launched, but the onResume event of that activity will trigger only after the previous one has paused.
I've also tried to list all the apps in foreground, but with no success, if I put my app in background resuming another app, my app always results to be in the foreground.
I read that since Android 4 there is a new method to know when the app is in foreground, but I need my app to be compatible with Android 3.0 devices too.
Here is the code I tried putting in every single activity (MyApp is my Application name):
#Override
protected void onResume() {
super.onResume();
MyApp.isPaused = false;
}
#Override
protected void onPause() {
super.onPause();
MyApp.isPaused = true;
}
This is also my attempt to list all the apps in foreground:
ActivityManager activityManager = (ActivityManager)((Activity) currentContext).getSystemService( ACTIVITY_SERVICE );
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for(RunningAppProcessInfo appProcess : appProcesses){
if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
if(appProcess.processName.equals("com.xxx.myapp")) {
Log.i("MyApp", "it's in foreground");
}
Log.i("MyApp", appProcess.processName);
}
}
This class provides a singleton to determine "the activity in background" status. It uses a timer with a threshold(i.e. 0.3s) to determine the activity is went to background or not.
One thing has to point out is that if the user resumes to the activity within the threshold (i.e. 0.3s), this test will be failed.
If you have a better solution, please share with us :)
Ref: https://gist.github.com/steveliles/11116937
You are absolutely correct :) Because only one activity can be alive at a time so you need something which remains alive through out the application life cycle :) like Application instance itself or you can also make use of shared preference for that matter. But seriously using shared prefference for checking lifecycle is wrong choice if you ask me.
If I was in your position I would have gone for Application class :) Here is code if you want to do the same :)
import android.app.Application;
/**
* Created by sandeepbhandari on 3/3/16.
*/
public class AppService extends Application{
private static AppService sInstance;
public static boolean isGoingToBackGround=false;
#Override
public void onCreate() {
super.onCreate();
sInstance = this;
}
public static AppService getInstance() {
return sInstance;
}
}
In all your activities onPause just set
AppService service = AppService.getInstance();
service.isGoingToBackGround =true;
And in onResume check the same variablethats all :) and yeah if you want to use your application class rather than default Application you have to make change to manifest.xml
<application
android:name=".AppService"
Thats all :)
Override onTrimMemory(int level) in your Application. Might not be the prettiest way, but it has worked for me.
You will get
TRIM_MEMORY_BACKGROUND = 40;
when your application went into the Background.
You can make Application class inside your project to save state of your project. When any activity goes to pause call on pause respectively while on resume call on resume method and save state of the inside this class. Even if one activity goes on pause another on resume your class will know exact state of the application. Or another way you can save applicaton state in shared preference in each activity can change its value.
i trust there is no need for u to post a code... that being said...
start by logging every implemented methods onCreate(), onPause(), onDestroy(), and other well reputed Activity methods...
but back button does not just pause it kills, thus onCreate is called most
and check onStart() too.
public class CustomApplication extends Application {
private static boolean activityVisible;
#Override
public void onCreate() {
super.onCreate();
}
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
}
and in your all activities set
#Override
protected void onResume() {
super.onResume();
CustomApplication.activityResumed();
}
#Override
protected void onPause() {
super.onPause();
CustomApplication.activityPaused();
}
and in your manifest
<application
android:name=".CustomApplication"

Android - Display notification when application is in background

I am using AlarmManager to periodically check for new content at some endpoint, validate if the results coming from the endpoint are the same as the ones I already have on my app, and if its not the same create a notification for each item.
What i need to know is how should i make the alarms to start only when the application is paused or stopped and cancel the alarms when de application is started or resumed.
where should i start the alarms and where should i cancel them?
In Android Notifications Guideline it says (on chapter: When not to display a notification):
Don't create a notification if the relevant new information is currently on screen. Instead, use the UI of the application itself to notify the user of new information directly in context. For instance, a chat application should not create system notifications while the user is actively chatting with another user.
If I have the application open i just want to disable alarms, when the application is closed/paused i want to cancel everything.
You need to create a Custom Application with global state and implement your own onPause and onResume at Application Level.
Create your own subclass of Application like this:
public class MyApplication extends Application {
private static MyApplication sInstance;
public MyApplication getInstance(){
return sInstance;
}
#Override
public void onCreate() {
super.onCreate();
sInstance = this;
}
public void onStart() {
// TODO: Stop your notification.
}
public void onStop() {
// TODO: Start your notification.
}
}
Specify its name in your AndroidManifest.xml's tag:
<application
android:icon="#drawable/icon"
android:label="#string/app_name"
android:name="MyApplication">
Create a class to hold the counts of activities:
public class ActiveActivitiesTracker {
private static int sActiveActivities = 0;
public static void activityStarted()
{
if (sActiveActivities == 0) {
// TODO: Here is presumably "application level" resume
MyApplication.getInstance().onStart();
}
sActiveActivities++;
}
public static void activityStopped()
{
sActiveActivities--;
if (sActiveActivities == 0) {
// TODO: Here is presumably "application level" pause
MyApplication.getInstance().onStop();
}
}
}
Then create a base activity (or do that in every activity), simply call the activityStarted() and activityStopped() methods:
#Override
public void onStart() {
super.onStart();
ActiveActivitiesTracker.activityStarted();
}
#Override
public void onStop() {
super.onStop();
ActiveActivitiesTracker.activityStopped();
}
For more details about Custom Application, see this.
For more details about Android Application Level Pause and Resume, see this.
Hope this helps.
you can try using a service and override in it , the onTrimMemory method and show the notificaton when "level" is equal to TRIM_MEMORY_UI_HIDDEN
#Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
switch (level) {
case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
break;
}
}
check the documentation for more info
http://developer.android.com/reference/android/content/ComponentCallbacks2.html#TRIM_MEMORY_UI_HIDDEN
I am not sure that this will be feasible within your project or if it will achieve what you hope to, however you could extend all of your activities from one base activity. In that base activity's onPause/onStop/onDestroy methods start the alarms and in that base activities onCreate/onStart methods cancel the alarms with the pending intent.
This will provide you with a set location from which you can handle your alarms if you have multiple activities from which the app may close.
You can learn more about the life cycle of activities here.

About launcher intent

I'm trying to make a certain function to start only when a user,
Opens the app for the first time,
Goes back to an app from home.
But not start if the user switches between activities within the app.
I have looked through this topic,and the best answer is to use singleTask with onNewIntent(). So, if a user is goes back to the app from Home, a onNewIntent call with the launcher intent passed to it can be used.
However, here is my code:
public class AdMobSDK_DFP_Interstitial extends Activity implements AdListener {
private static final String MOBMAX_INTERSTITIAL_AD_UNIT_ID = "/7732/test_portal7/android_app1_test_portal7/splash_banner_android_app1_test_portal7";
private DfpInterstitialAd interstitialAd;
private int num = 0;
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
Log.d("flow", "onNewIntent");
}
If I switch between different activities in the app, onNewIntent() is always called, which is the same as I go back to the app from Home.
First thing you can do is to implement your own "Application" object and have it run the needed function when it is created.
public class MyApplication extends Application {
#Override
public void onCreate() {
// Call your function
}
}
Your application object will be live as long as your app is alive (any activity/service is still running), but note that the Application object is not destroyed immediately when the user presses "Home", and might stay alive for a while and a user can return to it without the function being called.
If you need this function to run as part of your main activity, just save a flag in your Application context :
public boolean alreadyDisplayed = false; and then in your activity's onStart you can just call
if ((MyApplication)getApplication().alreadyDisplayed ) {
// Call your function
(MyApplication)getApplication().alreadyDisplayed = true;
}
** If this solution is not enough for you and you need to call your function every time your main activity is displayed from the home page you'll need to do something not as nice... one suggestion I can give you is to implement the same Application object but this time with an "open activity" counter:
public class MyApplication extends Application {
public int mActivityCounter = 0;
}
Then you can increment this counter on every onStart of activity in your app and decrement on every onStop (of course this can be done by implementing a class MyActivity and make all your relevant activities inherit it. Then you can use this counter to know if there are any other activities opened. Note that you'll have to make sure the access to this counter is synchronized and work your way with it as you need.
I hope this helps...

How to kill app on button press

I have an app that has a lot of activities. In the "Settings" page there is a delete account button that is supposed to reset all the saved variables and exit the app. I haven't found a simple solution to exiting the app (eg calling finish only destroys the current activity) What do I call to close the app on a button press (eg when I reopen the the app it should start from the first activity)
Easiest way to do this is to register a BroadcastReceiver in all Activity classes that listens for a specific Intent. When you want to close everything then just fire the matching Intent, and in the BroadcastReceiver in each Activity call finish.
Try System.exit(0), although you're technically suppose to use finish() on all the activities. This does the same, but quickly.
Use this:
Process.killProcess(Process.myPid());
Or there is another more safer approach. Just subclass all of your activities, from one parent Activity and keep list of all alive activities and then when necessary close them all using exit():
public class ControlActivity extends Activity
{
private static ArrayList<Activity> activities=new ArrayList<Activity>();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
activities.add(this);
}
#Override
public void onDestroy()
{
super.onDestroy();
activities.remove(this);
if(activities.size()==0) //last activity
//release resources and so on
}
//close all activities, when necessary
public static void exit()
{
for(Activity activity:activities)
activity.finish();
}
}

How can I tell if Android app is running in the foreground?

I am doing a status bar notification in my android app that is triggered by c2dm. I don't want to display the notification if the app is running. How do you determine if the app is running and is in the foreground?
Alternately, you can check with the ActivityManager what tasks are running by getRunningTasks method. Then check with the first task(task in the foreground) in the returned List of tasks, if it is your task. Here is the code example:
public Notification buildNotification(String arg0, Map<String, String> arg1) {
ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> services = activityManager
.getRunningTasks(Integer.MAX_VALUE);
boolean isActivityFound = false;
if (services.get(0).topActivity.getPackageName().toString()
.equalsIgnoreCase(appContext.getPackageName().toString())) {
isActivityFound = true;
}
if (isActivityFound) {
return null;
} else {
// write your code to build a notification.
// return the notification you built here
}
}
And don't forget to add the GET_TASKS permission in the manifest.xml file in order to be able to run getRunningTasks() method in the above code:
<uses-permission android:name="android.permission.GET_TASKS" />
p/s : If agree this way, please to note that this permission now is deprecated.
Make a global variable like private boolean mIsInForegroundMode; and assign a false value in onPause() and a true value in onResume().
Sample code:
private boolean mIsInForegroundMode;
#Override
protected void onPause() {
super.onPause();
mIsInForegroundMode = false;
}
#Override
protected void onResume() {
super.onResume();
mIsInForegroundMode = true;
}
// Some function.
public boolean isInForeground() {
return mIsInForegroundMode;
}
This is a pretty old post but still quite relevant. The above accepted solution may work but is wrong. 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 such what the next thing will be.
And the implementation and global behavior here is not guaranteed to remain the same in the future.
The correct solution is to implement : ActivityLifeCycleCallbacks.
This basically needs an Application Class and the handler can be set in there to identify the state of your activities in the app.
As Vinay says, probably the best solution (to support newer android versions, 14+) is to use ActivityLifecycleCallbacks in the Application class implementation.
package com.telcel.contenedor.appdelegate;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;
/** Determines global app lifecycle states.
*
* The following is the reference of activities states:
*
* The <b>visible</b> lifetime of an activity happens between a call to onStart()
* until a corresponding call to onStop(). During this time the user can see the
* activity on-screen, though it may not be in the foreground and interacting with
* the user. The onStart() and onStop() methods can be called multiple times, as
* the activity becomes visible and hidden to the user.
*
* The <b>foreground</b> lifetime of an activity happens between a call to onResume()
* until a corresponding call to onPause(). During this time the activity is in front
* of all other activities and interacting with the user. An activity can frequently
* go between the resumed and paused states -- for example when the device goes to
* sleep, when an activity result is delivered, when a new intent is delivered --
* so the code in these methods should be fairly lightweight.
*
* */
public class ApplicationLifecycleManager implements ActivityLifecycleCallbacks {
/** Manages the state of opened vs closed activities, should be 0 or 1.
* It will be 2 if this value is checked between activity B onStart() and
* activity A onStop().
* It could be greater if the top activities are not fullscreen or have
* transparent backgrounds.
*/
private static int visibleActivityCount = 0;
/** Manages the state of opened vs closed activities, should be 0 or 1
* because only one can be in foreground at a time. It will be 2 if this
* value is checked between activity B onResume() and activity A onPause().
*/
private static int foregroundActivityCount = 0;
/** Returns true if app has foreground */
public static boolean isAppInForeground(){
return foregroundActivityCount > 0;
}
/** Returns true if any activity of app is visible (or device is sleep when
* an activity was visible) */
public static boolean isAppVisible(){
return visibleActivityCount > 0;
}
public void onActivityCreated(Activity activity, Bundle bundle) {
}
public void onActivityDestroyed(Activity activity) {
}
public void onActivityResumed(Activity activity) {
foregroundActivityCount ++;
}
public void onActivityPaused(Activity activity) {
foregroundActivityCount --;
}
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
public void onActivityStarted(Activity activity) {
visibleActivityCount ++;
}
public void onActivityStopped(Activity activity) {
visibleActivityCount --;
}
}
And in Application onCreate() method:
registerActivityLifecycleCallbacks(new ApplicationLifecycleManager());
Then ApplicationLifecycleManager.isAppVisible() or ApplicationLifecycleManager.isAppInForeground() would be used to know the desired state.
Since API 16 you can do it like this:
static boolean shouldShowNotification(Context context) {
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
if (myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
return true;
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
// app is in foreground, but if screen is locked show notification anyway
return km.inKeyguardRestrictedInputMode();
}
FYI, if you use Gadenkan solution (which is great!!) don't forget to add
<uses-permission android:name="android.permission.GET_TASKS" />
to the manifest.
Slightly cleaned up version of Gadenkan's solution. Put it any Activity, or maybe a base class for all your Activities.
protected boolean isRunningInForeground() {
ActivityManager manager =
(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1);
if (tasks.isEmpty()) {
return false;
}
String topActivityName = tasks.get(0).topActivity.getPackageName();
return topActivityName.equalsIgnoreCase(getPackageName());
}
To be able to call getRunningTasks(), you need to add this in your AndroidManifest.xml:
<uses-permission android:name="android.permission.GET_TASKS"/>
Do note what ActivityManager.getRunningTasks() Javadoc says though:
Note: this method is only intended for debugging and presenting task
management user interfaces. This should never be used for core logic
in an application, such as deciding between different behaviors based
on the information found here. Such uses are not supported, and will
likely break in the future.
Update (Feb 2015)
Note that getRunningTasks() was deprecated in API level 21!
As of LOLLIPOP, this
method is no longer available to third party applications: the
introduction of document-centric recents means it can leak person
information to the caller. For backwards compatibility, it will still
return a small subset of its data: at least the caller's own tasks,
and possibly some other tasks such as home that are known to not be
sensitive.
So what I wrote earlier is even more relevant:
In many cases you can probably come up with a better solution. For example, doing something in onPause() and onResume(), perhaps in a BaseActivity for all your Activities.
(In our case we didn't want an offline alert activity to be launched if we are not in the foreground, so in BaseActivity onPause() we simply unsubscribe from the RxJava Subscription listening for "went offline" signal.)
Following up on Gadenkan's reply I needed something like this so I could tell if my app wasn't running in the foreground, but I needed something that was app wide and didn't require me setting/unsetting flags throughout my application.
Gadenkan's code pretty much hit the nail on the head but it wasn't in my own style and felt it could be tidier, so in my app its condensed down to this.
if (!context.getPackageName().equalsIgnoreCase(((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1).get(0).topActivity.getPackageName()))
{
// App is not in the foreground
}
(Side note: You can just remove the ! if you want the check to work the other way around)
Although with this approach you need the GET_TASKS permission.
Starting support library version 26 you can use ProcessLifecycleOwner to determine app current state, just add it to your dependencies 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
}
, Now you can query ProcessLifecycleOwner whenever you want to check app state, for example to check if app is running in foreground you just have to do this:
boolean isAppInForeground = ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
if(!isAppInForeground)
//Show Notification in status bar
Based on the various answers and comments, here is a more inlined version that you can add to a helper class:
public static boolean isAppInForeground(Context context) {
List<RunningTaskInfo> task =
((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE))
.getRunningTasks(1);
if (task.isEmpty()) {
return false;
}
return task
.get(0)
.topActivity
.getPackageName()
.equalsIgnoreCase(context.getPackageName());
}
As mentioned in other answers you need to add the following permission to your AndroidManifest.xml .
<uses-permission android:name="android.permission.GET_TASKS"/>
I would like to add that a safer way to do this - than checking if your app is in the background before creating a notification - is to just disable and enable the Broadcast Receiver onPause() and onResume() respectively.
This method gives you more control in the actual application logic and is not likely to change in the future.
#Override
protected void onPause() {
unregisterReceiver(mHandleMessageReceiver);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
}
I found a more simpler and accurate way to check if the application is in foreground or background by mapping the activities to boolean.
Check the complete gist here
Here's the code for nice simple solution described above by #user2690455 . Although it looks a bit verbose, you'll see overall it's actually quite light-weight
In my case we also use AppCompatActivity, so I had to have 2 base classes.
public class BaseActivity extends Activity {
/**
* Let field be set only in base class
* All callers must use accessors,
* and then it's not up to them to manage state.
*
* Making it static since ..
* 1. It needs to be used across two base classes
* 2. It's a singleton state in the app
*/
private static boolean IS_APP_IN_BACKGROUND = false;
#Override
protected void onResume() {
super.onResume();
BaseActivity.onResumeAppTracking(this);
BaseActivity.setAppInBackgroundFalse();
}
#Override
protected void onStop() {
super.onStop();
BaseActivity.setAppInBackgroundTrue();
}
#Override
protected void onPause() {
super.onPause();
BaseActivity.setAppInBackgroundFalse();
}
protected static void onResumeAppTracking(Activity activity) {
if (BaseActivity.isAppInBackground()) {
// do requirements for returning app to foreground
}
}
protected static void setAppInBackgroundFalse() {
IS_APP_IN_BACKGROUND = false;
}
protected static void setAppInBackgroundTrue() {
IS_APP_IN_BACKGROUND = true;
}
protected static boolean isAppInBackground() {
return IS_APP_IN_BACKGROUND;
}
}
This is useful only when you want to perform some action just when your activity starts and its where you want to check if app is in foreground or background.
Instead of using Activity manager there is a simple trick which you can do through code.
If you observe the activity cycle closely, the flow between two activities and foreground to background is as follows.
Suppose A and B are two activities.
When transition from A to B:
1. onPause() of A is called
2. onResume() of B is called
3. onStop() of A is called when B is fully resumed
When app goes into background:
1. onPause() of A is called
2. onStop() of A is called
You can detect your background event by simply putting a flag in activity.
Make an abstract activity and extend it from your other activities, so that you wont have to copy paste the code for all other activities wherever you need background event.
In abstract activity create flag isAppInBackground.
In onCreate() method:
isAppInBackground = false;
In onPause() method:
isAppInBackground = false;
In onStop() method:
isAppInBackground = true;
You just to need to check in your onResume() if isAppInBackground is true.
n after you check your flag then again set isAppInBackground = false
For transition between two activities since onSTop() of first will always called after second actvity resumes, flag will never be true and when app is in background, onStop() of activity will be called immediately after onPause and hence the flag will be true when you open the app later on.
There is one more scenario though in this approach.
If any of your app screen is already open and you put the mobile idle then after some time mobile will go into sleep mode and when you unlock mobile, it will be treated at background event.
Here is a method that I use (and supporting method):
private boolean checkIfAppIsRunningInForeground() {
ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
for(ActivityManager.RunningAppProcessInfo appProcessInfo : activityManager.getRunningAppProcesses()) {
if(appProcessInfo.processName.contains(this.getPackageName())) {
return checkIfAppIsRunningInForegroundByAppImportance(appProcessInfo.importance);
}
}
return false;
}
private boolean checkIfAppIsRunningInForegroundByAppImportance(int appImportance) {
switch (appImportance) {
//user is aware of app
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND:
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE:
return true;
//user is not aware of app
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND:
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY:
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE:
case ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE:
default:
return false;
}
}
There is no global callback for this, but for each activity it is onStop(). You don't need to mess with an atomic int. Just have a global int with the number of started activities, in every activity increment it in onStart() and decrement it in onStop().
Follow this
public static boolean isAppRunning(Context context) {
// check with the first task(task in the foreground)
// in the returned list of tasks
ActivityManager activityManager = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> services =
activityManager.getRunningTasks(Integer.MAX_VALUE);
if
(services.get(0).topActivity.getPackageName().toString().equalsIgnoreCase(context.getPackageName().toString()))
{
return true;
}
return false;
}
The previous approaches mentioned here are not optimal. The task based approach requires a permission that might not be desired and "Boolean" approach is prone to concurrent modification mess ups.
The approach I use and which (I believe) works quite well in most cases:
Have a "MainApplication" class to track activity count in AtomicInteger:
import android.app.Application;
import java.util.concurrent.atomic.AtomicInteger;
public class MainApplication extends Application {
static class ActivityCounter {
private static AtomicInteger ACTIVITY_COUNT = new AtomicInteger(0);
public static boolean isAppActive() {
return ACTIVITY_COUNT.get() > 0;
}
public static void activityStarted() {
ACTIVITY_COUNT.incrementAndGet();
}
public static void activityStopped() {
ACTIVITY_COUNT.decrementAndGet();
}
}
}
And create a base Activity class that other activities would extend:
import android.app.Activity;
import android.support.annotation.CallSuper;
public class TestActivity extends Activity {
#Override
#CallSuper
protected void onStart() {
MainApplication.ActivityCounter.activityStarted();
super.onStart();
}
#Override
#CallSuper
protected void onStop() {
MainApplication.ActivityCounter.activityStopped();
super.onStop();
}
}

Categories

Resources