-1

this question has been asked like a hundred times but all i could fine have the same answer using

getRunningAppProcesses()

which doesn't work properly on Lollipop

so it there a completely reliable way to know if my app is alive in the background?

Thank you

EDIT:

This's what i use to check if the app in the foreground:

the preferences used:

    public static void setStartingActivity(Context context, boolean isStartingActivity) {
        PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("isStartingActivity", isStartingActivity).apply();
    }

    public static boolean isStartingActivity(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("isStartingActivity", false);
    }

    public static void setAppRunningInForeground(Context context, boolean isRunning) {
        PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("AppIsRunningInForeground", isRunning).apply();
    }

    public static boolean isAppRunningForeground(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("AppIsRunningInForeground", false);
    }

starting the activity:

Utility.PreferencesManager.setStartingActivity(getApplicationContext(), true);
startActivity(new Intent(getApplicationContext(), MainActivity.class));

the onStop and onStart implementation:

@Override
protected void onStart() {
    super.onStart();
    Log.e("Debugging", "MainActivity onStart");
    Utility.PreferencesManager.setAppRunningInForeground(getApplicationContext(), true);
}

@Override
protected void onStop() {
    super.onStop();
    Log.e("Debugging", "MainActivity onStop");

    if (!Utility.PreferencesManager.isStartingActivity(getApplicationContext()))
        Utility.PreferencesManager.setAppRunningInForeground(getApplicationContext(), false);
    else
        Utility.PreferencesManager.setStartingActivity(getApplicationContext(), false);
}
Ahmed Mourad
  • 193
  • 1
  • 2
  • 18
  • Have you tried [onPause](https://developer.android.com/guide/components/activities/activity-lifecycle.html#onpause) – Derek Apr 13 '17 at 21:45
  • I think this is what are looking for: http://stackoverflow.com/questions/30619349/android-5-1-1-and-above-getrunningappprocesses-returns-my-application-packag – Walter Palladino Apr 13 '17 at 21:46
  • Usually, there are better solutions for whatever it is that you are trying to accomplish here. What exactly do you intend to do with the information about whether you are in the foreground or the background? – CommonsWare Apr 13 '17 at 21:47
  • @Really-Brad-Larson i wouldn't have a way then to know if then app has been killed by swiping or still in the background – Ahmed Mourad Apr 13 '17 at 22:08
  • @CommonsWare i'm trying to prevent the sync adapter from doing its periodic sync while the app is running either in foreground or background, managed to check if it's in foreground but background remains the problem – Ahmed Mourad Apr 13 '17 at 22:10
  • @AhmedMourad couldn't you assume if checking the foreground failed that you would be in the background? – Derek Apr 13 '17 at 22:18
  • @CommonsWare great reference thanks, but says it will only work until android 6.0 and won't work beyond that – Ahmed Mourad Apr 13 '17 at 22:19
  • @Really-Brad-Larson the app could also be killed, in order to check if it's in the foreground i'm using preference manager with onStop and onStart methods – Ahmed Mourad Apr 13 '17 at 22:20
  • @AhmedMourad I would then suggest a [Service](https://developer.android.com/reference/android/app/Service.html) as you won't be relying on the user – Derek Apr 13 '17 at 22:25
  • "while the app is running either in foreground or background" -- if by "running in the background", you mean that you are actively doing some work in an `IntentService` or something, that's fine. A typical solution there is to just have the service update some `static boolean` in `onCreate()` and `onDestroy()`, so you would check the `boolean` in your sync adapter. – CommonsWare Apr 13 '17 at 22:28
  • With regards to foreground UI, I would have a custom `Application` override `onTrimMemory()` and cache the last-seen value, and make decisions based on that. – CommonsWare Apr 13 '17 at 22:29
  • @Really-Brad-Larson i updated the question with what i use to check if it's in foreground or not – Ahmed Mourad Apr 13 '17 at 22:29
  • @CommonsWare what i mean by background is the user clicking the home button sending the app to the background but without killing it so he could restore it a anytime, don't have a service in the app, sorry if i haven't been clear with my question – Ahmed Mourad Apr 13 '17 at 22:32
  • @CommonsWare i don't really get what you mean there with the Application and onTrimMemory() – Ahmed Mourad Apr 13 '17 at 22:36
  • I thought that you were trying to only do the sync when your UI was in the background, and `onTrimMemory()` can help you determine that in about two lines of code. However, you seem to want to block syncs even if the UI is in the background, and IMHO that is not a good plan. The user can "restore it a anytime" 24 hours a day, 7 days a week. There is nothing particularly special about a UI in the background compared to a UI not existing. – CommonsWare Apr 13 '17 at 22:39
  • @CommonsWare could reset the app to its initial state if the sync was done while it's in the background and then it was brought back to foreground but was thinking it was bad practice, it isn't? – Ahmed Mourad Apr 13 '17 at 22:44
  • Well, you need to write your sync adapter not to break things for the user. You need to do that anyway, as the user could go back into your app mid-sync. If you wanted to block starting a new sync if the user has been in your UI recently (e.g., within the past few minutes), that's reasonable. But if Android happens to keep your process around for hours, saying that you are not going to sync with the server because the user happened to be in your UI hours ago is not a good plan IMHO. – CommonsWare Apr 13 '17 at 22:46
  • @CommonsWare The thing is the app is fetching data from TMDB API by page with each page having 20 movies, so i store the maximum page the user has reached by day so if he was on say page 4 and sync happened it would restore max page counter to 1 which would mess up the process of fetching data from the offline database getting page 4 as page 2, so looks like i'll have to refactor the database, content provider and sync adapter ... long night i see, anyways is there a way to check if the user has sent the app to background few minutes ago as you mention here? – Ahmed Mourad Apr 13 '17 at 22:57

1 Answers1

0

Blocking syncs when the UI is around is not going to solve your problem, simply because the user may return to your UI while you are in the middle of a sync. You need to be able to handle this situation.

Avoiding syncs when the user has recently been in your UI, for some short value of "recently", may help reduce the odds that the user will return to your UI while the app is syncing.

Based on your comments, let's assume that your app consists of 1+ activities plus your sync adapter. When your sync adapter runs, you want to determine if the user has been in the UI recently for this process.

There are three possibilities:

  1. The UI is in the foreground when the sync adapter runs

  2. The UI is in the background when the sync adapter runs

  3. There is no UI, as the last process that had your UI had been terminated, and your sync adapter is running in a fresh process with no UI bits

Off the cuff, to handle that, I would have a custom Application, with two boolean fields:

  • areActivitiesCreated, which will be true if this process ever created an activity, false by default

  • isInBackground, which will be true if the app is in the background, false otherwise

I would have the Application call registerActivityLifecycleCallbacks(), and set areActivitiesCreated to true in onActivityCreated of the callback.

I would have the Application override onTrimMemory(), and update isInBackground based on the passed-in trim level, setting it to false if the trim level is one of the TRIM_MEMORY_RUNNING_* values, or true otherwise.

Then, your sync adapter would go ahead and do its work if either areActivitiesCreated is false (meaning that you have no UI) or if isInBackground is true (meaning that you are not in the foreground).

This avoids the need to add code to all the activities to track this condition.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491