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 up
Use this code for API 21 or above. This works and gives better result compared to the other answers, it detects perfectly the foreground process.
if (Build.VERSION.SDK_INT >= 21) {
String currentApp = null;
UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> applist = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time);
if (applist != null && applist.size() > 0) {
SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
for (UsageStats usageStats : applist) {
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
}
if (mySortedMap != null && !mySortedMap.isEmpty()) {
currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
}
If you only want to know the application containing the current activity, you can do so using ActivityManager. The technique you can use depends on the version of Android:
ActivityManager.RunningAppProcessInfo.processState
public class CurrentApplicationPackageRetriever {
private final Context context;
public CurrentApplicationPackageRetriever(Context context) {
this.context = context;
}
public String get() {
if (Build.VERSION.SDK_INT < 21)
return getPreLollipop();
else
return getLollipop();
}
private String getPreLollipop() {
@SuppressWarnings("deprecation")
List<ActivityManager.RunningTaskInfo> tasks =
activityManager().getRunningTasks(1);
ActivityManager.RunningTaskInfo currentTask = tasks.get(0);
ComponentName currentActivity = currentTask.topActivity;
return currentActivity.getPackageName();
}
private String getLollipop() {
final int PROCESS_STATE_TOP = 2;
try {
Field processStateField = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");
List<ActivityManager.RunningAppProcessInfo> processes =
activityManager().getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo process : processes) {
if (
// Filters out most non-activity processes
process.importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
&&
// Filters out processes that are just being
// _used_ by the process with the activity
process.importanceReasonCode == 0
) {
int state = processStateField.getInt(process);
if (state == PROCESS_STATE_TOP) {
String[] processNameParts = process.processName.split(":");
String packageName = processNameParts[0];
/*
If multiple candidate processes can get here,
it's most likely that apps are being switched.
The first one provided by the OS seems to be
the one being switched to, so we stop here.
*/
return packageName;
}
}
}
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
return null;
}
private ActivityManager activityManager() {
return (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
}
}
Add the GET_TASKS permission to AndroidManifest.xml
:
<!--suppress DeprecatedClassUsageInspection -->
<uses-permission android:name="android.permission.GET_TASKS" />
I could not find a solution that our team would be happy with so we rolled our own. We use ActivityLifecycleCallbacks
to keep track of current activity and then expose it through a service:
public interface ContextProvider {
Context getActivityContext();
}
public class MyApplication extends Application implements ContextProvider {
private Activity currentActivity;
@Override
public Context getActivityContext() {
return currentActivity;
}
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
MyApplication.this.currentActivity = activity;
}
@Override
public void onActivityStarted(Activity activity) {
MyApplication.this.currentActivity = activity;
}
@Override
public void onActivityResumed(Activity activity) {
MyApplication.this.currentActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
MyApplication.this.currentActivity = null;
}
@Override
public void onActivityStopped(Activity activity) {
// don't clear current activity because activity may get stopped after
// the new activity is resumed
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
// don't clear current activity because activity may get destroyed after
// the new activity is resumed
}
});
}
}
Then configure your DI container to return instance of MyApplication
for ContextProvider
, e.g.
public class ApplicationModule extends AbstractModule {
@Provides
ContextProvider provideMainActivity() {
return MyApplication.getCurrent();
}
}
(Note that implementation of getCurrent()
is omitted from the code above. It's just a static variable that's set from the application constructor)
Here is my answer that works just fine...
You should be able to get current Activity in this way... If you structure your app with a few Activities with many fragments and you want to keep track of what is your current Activity, it would take a lot of work though. My senario was I do have one Activity with multiple Fragments. So I can keep track of Current Activity through Application Object, which can store all of the current state of Global variables.
Here is a way. When you start your Activity, you store that Activity by Application.setCurrentActivity(getIntent()); This Application will store it. On your service class, you can simply do like Intent currentIntent = Application.getCurrentActivity(); getApplication().startActivity(currentIntent);
Just recently found out about this. With apis as:
targetSdkVersion 26
ActivityManager.getCurrentActivity(context)
Hope this is of any use.
Is there a native android way to get a reference to the currently running Activity from a service?
You may not own the "currently running Activity".
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)?
Intent
to the activity -- here is a sample project demonstrating this patternPendingIntent
(e.g., via createPendingResult()
) that the service invokesbindService()
, and have the service call an event method on that callback/listener objectIntent
to the activity, with a low-priority BroadcastReceiver
as backup (to raise a Notification
if the activity is not on-screen) -- here is a blog post with more on this pattern