Android: How can I get the current foreground activity (from a service)?

Viewed 307797

Is there a native android way to get a reference to the currently running Activity from a service?

I have a service running on the background, and I would like to update my current Activity when an event occurs (in the service). Is there a easy way to do that (like the one I suggested above)?

13 Answers

Update: this no longer works with other apps' activities as of Android 5.0


Here's a good way to do it using the activity manager. You basically get the runningTasks from the activity manager. It will always return the currently active task first. From there you can get the topActivity.

Example here

There's an easy way of getting a list of running tasks from the ActivityManager service. You can request a maximum number of tasks running on the phone, and by default, the currently active task is returned first.

Once you have that you can get a ComponentName object by requesting the topActivity from your list.

Here's an example.

    ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
    Log.d("topActivity", "CURRENT Activity ::" + taskInfo.get(0).topActivity.getClassName());
    ComponentName componentInfo = taskInfo.get(0).topActivity;
    componentInfo.getPackageName();

You will need the following permission on your manifest:

<uses-permission android:name="android.permission.GET_TASKS"/>

Here's what I suggest and what has worked for me. In your application class, implement an Application.ActivityLifeCycleCallbacks listener and set a variable in your application class. Then query the variable as needed.

class YourApplication: Application.ActivityLifeCycleCallbacks {
    
    var currentActivity: Activity? = null

    fun onCreate() {
        registerActivityLifecycleCallbacks(this)
    }

    ...
    
    override fun onActivityResumed(activity: Activity) {
        currentActivity = activity
    }
}

I like the idea of the Application.ActivityLifecycleCallbacks. But it can be a bit tricky getting the top activity

  • Your app might have multiple activities
  • Some activities might get destroyed
  • Some activities might go to background

To handle all those cases, you need to track each activity life cycle. This is exactly what I did with my below solution.

It all consolidates into a single call of getTopForegroundActivity() that returns the top foreground activity or null if no activities in the stack or non of them are in the foreground.

Usage

public class MyApp extends Application {

    private ActivityTracker activityTracker;

    @Override
    public void onCreate() {
        super.onCreate();

        activityTracker = new ActivityTracker();
        registerActivityLifecycleCallbacks(activityTracker);
        
        ...

        Activity activity = activityTracker.getTopForegroundActivity();
        if(activity != null) {
            // Do something
        }
    }
}

Source

public class ActivityTracker implements Application.ActivityLifecycleCallbacks {
    private final Map<Activity, ActivityData> activities = new HashMap<>();


    public Activity getTopForegroundActivity() {
        if (activities.isEmpty()) {
            return null;
        }
        ArrayList<ActivityData> list = new ArrayList<>(activities.values());
        Collections.sort(list, (o1, o2) -> {
            int compare = Long.compare(o2.started, o1.started);
            return compare != 0 ? compare : Long.compare(o2.resumed, o1.resumed);
        });

        ActivityData topActivity = list.get(0);
        return topActivity.started != -1 ? topActivity.activity : null;
    }


    @Override
    public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
        activities.put(activity, new ActivityData(activity));
    }

    @Override
    public void onActivityStarted(@NonNull Activity activity) {
        ActivityData activityData = activities.get(activity);
        if (activityData != null) {
            activityData.started = System.currentTimeMillis();
        }
    }

    @Override
    public void onActivityResumed(@NonNull Activity activity) {
        ActivityData activityData = activities.get(activity);
        if (activityData != null) {
            activityData.resumed = System.currentTimeMillis();
        }
    }

    @Override
    public void onActivityPaused(@NonNull Activity activity) {
        ActivityData activityData = activities.get(activity);
        if (activityData != null) {
            activityData.resumed = -1;
        }
    }

    @Override
    public void onActivityStopped(@NonNull Activity activity) {
        ActivityData activityData = activities.get(activity);
        if (activityData != null) {
            activityData.started = -1;
        }
    }

    @Override
    public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {

    }

    @Override
    public void onActivityDestroyed(@NonNull Activity activity) {
        activities.remove(activity);
    }

    private static class ActivityData {

        public final Activity activity;
        public long started;
        public long resumed;

        private ActivityData(Activity activity) {
            this.activity = activity;
        }
    }
}
Related