2

The official documentation describes tasks as follows:

*All the activities in a task move together as a unit. The entire task (the entire activity stack) can be brought to the foreground or sent to the background. Suppose, for instance, that the current task has four activities in its stack — three under the current activity. The user presses the HOME key, goes to the application launcher, and selects a new application (actually, a new task). The current task goes into the background and the root activity for the new task is displayed. Then, after a short period, the user goes back to the home screen and again selects the previous application (the previous task). That task, with all four activities in the stack, comes forward.

Is there a way to programmatically detect when the task of the current Activity moves into and out of the background? I would like to know when the user has switched switched to another application, vs. when the user navigated to another Activity in the current app.

zer0stimulus
  • 22,306
  • 30
  • 110
  • 141
  • It may help if you can tell us what the purpose of detect that is? – EboMike Jul 23 '10 at 03:40
  • My business logic is different based on the two cases. The background activity binds to a remote service in the background. If the user is actually switching task, I would like this background activity to unbind. Otherwise, it needs to keep binding in order to expose the service to other activities in my app. – zer0stimulus Jul 23 '10 at 13:23

8 Answers8

4

Note: I've always had this design in my head but never got around to concrete tests (reasonably sure it works though), so if you end up trying this, tell me how it goes. :)


I don't think there's an official API method that'll give you this functionality (I may be wrong), but you can certainly construct your own. This is just my way of doing it; there may, of course, be better implementations.

In your application, you always know when you're starting another activity. With that said, you can create a global class that handles starting all of your application activities and keeps track of a boolean that represents when you're starting an activity:

public class GlobalActivityManager {

    private static boolean isActivityStarting = true;

    public static boolean isActivityStarting() {
        return isActivityStarting;
    }

    public static void setIsActivityStarting(boolean newValue) {
        isActivityStarting = newValue;
    }

    public static void startActivity(Activity previous, Class activityClass) {
        isActivityStarting = true;
        // Do stuff to start your activity
        isActivityStarting = false;
    }
}

Then in each of your activities (maybe make this a superclass), override the onPause() method to check if it's another one of your application's activities starting or a foreign task's application coming in front of your application. This works because onPause is executed when anything comes in front of the activity, meaning it's called when you start your activity in GlobalActivityManager where isActivityStarting is true.

public void onPause() {
    super.onPause();
    if (GlobalActivityManager.isActivityStarting()) {
        // It's one of your application's activities. Everything's normal.
    } else {
        // Some other task has come to the foreground. Do what needs to be done.
    }
}
Andy Zhang
  • 8,285
  • 1
  • 37
  • 24
  • See what James said below regarding Back button, which will cause the current (foreground) Activity's onPause method to get called when startActivity was not. So maybe override the Back button (I think this is possible) to detect that appropriately. But it seems in general more work is needed here. – Fraggle Mar 26 '11 at 23:20
3
    public boolean isCurrentTaskInBackground() {
    List<RunningTaskInfo> taskInfoList = mActivityManager.getRunningTasks(1);
    if (taskInfoList != null && taskInfoList.size() > 0) {
        RunningTaskInfo info = taskInfoList.get(0);

        ComponentName componentName = info.baseActivity;

        MobileTvLog.debug("App#isCurrentTaskInBackground -> baseActivity = " + componentName);

        String packageName = componentName.getPackageName();

        return !YOUR_PKG_NAME.equals(packageName);
    } else {
        return true;
    }
}
shaobin0604
  • 1,179
  • 12
  • 14
2

Maybe this can be helpfull, tell me if it worked for you. only when you return from background the value of activities would be 0 (zero) the rest of the time would be a number higher than 0(zero) when the onRestart() is executed.

public class FatherClass extends Activity {

private static int activities = 0;

public void onCreate(Bundle savedInstanceState, String clase) {
    super.onCreate(savedInstanceState);
}

protected void onRestart()
{
    super.onRestart();
    if(activities == 0){
        Log.i("APP","BACK FROM BACKGROUND");
    }
}

protected void onStop(){
    super.onStop();
    activities -= 1;
}

protected void onStart(){
    super.onStart();
    activities += 1;
}

}


All of your classes must extend from this class for this to work.

Sebastian Nowak
  • 5,607
  • 8
  • 67
  • 107
Jorge Aguilar
  • 3,442
  • 30
  • 34
  • static variables can be garbage collected under android (without you noticing it) and can be reset when you press the home button. This implementation is _guaranteed_ to fail at some point. – meredrica Jun 12 '13 at 11:20
  • Like you said the home button can set it back to 0 and that is exactly what you want in this case that this be 0 when you go out of the whole app and also normally the garbage collector removing this variable is more plausible when you go out to other app and then when you return this can happen but again you get the exact result you want (the variable to be 0). But you are right it can also happen that even inside of your own app the garbage collector can remove your variable but is a not that possible scenario i think. – Jorge Aguilar Jun 12 '13 at 11:59
  • It is a possible scenario. Just use some 2.2 Phone that has low memory and push a new Activity. – meredrica Jun 12 '13 at 17:05
1

That will not work. Your activity could get an onPause for reasons other than your app explicitly starting another activity. For instance, the user could have hit the back button, taking you back to a previous Activity in your stack.

james
  • 11
  • 1
1

Try to read about android:finishOnTaskLaunch

http://developer.android.com/guide/topics/manifest/activity-element.html#finish

It solved my similiar problem ;-)

neteinstein
  • 17,529
  • 11
  • 93
  • 123
0

I've been looking for a good answer to this question. It seems Andy Zhang had a good idea, but it may need a bit more work to handle other things, like the Back button.

Another approach which seems promising is to use the ActivityManager.getRunningAppProcesses() method, which will give you a list of RunningAppProcessInfo which each have an "importance" variable which can be used to detect if your process is in the foreground or other states.

The problem of course is there is no Detection technique here, just a way to tell what is running and its state, but no way to get informed when the state changes.

So possibly just run a background thread to poll this info. Seems a bit kludgy but it might work.

My app uses location services (GPS) so it automatically gets called when the location changes, and I can check the RunningAppProcessInfo list when this happens to determine if my App is still in the foreground. Seems like a lot of work, so maybe Andy's approach can be improved on.

Fraggle
  • 8,607
  • 7
  • 54
  • 86
0

I have been using the method I describe here:

Simple check for Android application backgrounding

It has been working wonderfully for me.

Community
  • 1
  • 1
Captain Blammo
  • 1,897
  • 20
  • 31
0

you might be able to use the isFinishing() method in onPause(). That will tell you if the application is actually finishing or is just being paused. When your task stack goes to the background, the activities aren't finished, they are just paused. This will also get called if you start another activity from this one though, so you would have to check for that.

@Override
public void onPause() {
    super.onPause();
    if(!isFinishing()) {
        //app going to background
    }
}
Cameron Ketcham
  • 7,966
  • 2
  • 28
  • 27