Android 从后台任务或服务中确定当前的前台应用程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2166961/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Determining the current foreground application from a background task or service
提问by dhaiwat
I wish to have one application that runs in the background, which knows when any of the built-in applications (messaging, contacts, etc) is running.
我希望有一个在后台运行的应用程序,它知道任何内置应用程序(消息、联系人等)何时运行。
So my questions are:
所以我的问题是:
How I should run my application in the background.
How my background application can know what the application currently running in the foreground is.
我应该如何在后台运行我的应用程序。
我的后台应用程序如何知道当前在前台运行的应用程序是什么。
Responses from folks with experience would be greatly appreciated.
非常感谢有经验的人的回应。
回答by Oliver Pearmain
With regards to "2. How my background application can know what the application currently running in the foreground is."
关于“2.我的后台应用程序如何知道当前在前台运行的应用程序是什么”。
Do NOT use the getRunningAppProcesses()
method as this returns all sorts of system rubbish from my experience and you'll get multiple results which have RunningAppProcessInfo.IMPORTANCE_FOREGROUND
. Use getRunningTasks()
instead
不要使用该getRunningAppProcesses()
方法,因为根据我的经验,这会返回各种系统垃圾,并且您会得到多个结果,其中包含RunningAppProcessInfo.IMPORTANCE_FOREGROUND
. 使用getRunningTasks()
替代
This is the code I use in my service to identify the current foreground application, its really easy:
这是我在我的服务中用来识别当前前台应用程序的代码,它真的很简单:
ActivityManager am = (ActivityManager) AppService.this.getSystemService(ACTIVITY_SERVICE);
// The first in the list of RunningTasks is always the foreground task.
RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
Thats it, then you can easily access details of the foreground app/activity:
就是这样,然后您可以轻松访问前台应用程序/活动的详细信息:
String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName();
PackageManager pm = AppService.this.getPackageManager();
PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
String foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
This requires an additional permission in activity menifest and works perfectly.
这需要在活动清单中获得额外许可并且完美运行。
<uses-permission android:name="android.permission.GET_TASKS" />
回答by Sven Dawitz
i had to figure out the right solution the hard way. the below code is part of cyanogenmod7 (the tablet tweaks) and is tested on android 2.3.3 / gingerbread.
我不得不以艰难的方式找出正确的解决方案。下面的代码是 cyanogenmod7(平板电脑调整)的一部分,并在 android 2.3.3/gingerbread 上进行了测试。
methods:
方法:
- getForegroundApp - returns the foreground application.
- getActivityForApp - returns the activity of the found app.
- isStillActive - determines if a earlier found app is still the active app.
- isRunningService - a helper function for getForegroundApp
- getForegroundApp - 返回前台应用程序。
- getActivityForApp - 返回找到的应用程序的活动。
- isStillActive - 确定较早找到的应用程序是否仍然是活动应用程序。
- isRunningService - getForegroundApp 的辅助函数
this hopefully answers this issue in all extend (:
这有望在所有扩展中回答这个问题(:
private RunningAppProcessInfo getForegroundApp() {
RunningAppProcessInfo result=null, info=null;
if(mActivityManager==null)
mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
List <RunningAppProcessInfo> l = mActivityManager.getRunningAppProcesses();
Iterator <RunningAppProcessInfo> i = l.iterator();
while(i.hasNext()){
info = i.next();
if(info.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND
&& !isRunningService(info.processName)){
result=info;
break;
}
}
return result;
}
private ComponentName getActivityForApp(RunningAppProcessInfo target){
ComponentName result=null;
ActivityManager.RunningTaskInfo info;
if(target==null)
return null;
if(mActivityManager==null)
mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
List <ActivityManager.RunningTaskInfo> l = mActivityManager.getRunningTasks(9999);
Iterator <ActivityManager.RunningTaskInfo> i = l.iterator();
while(i.hasNext()){
info=i.next();
if(info.baseActivity.getPackageName().equals(target.processName)){
result=info.topActivity;
break;
}
}
return result;
}
private boolean isStillActive(RunningAppProcessInfo process, ComponentName activity)
{
// activity can be null in cases, where one app starts another. for example, astro
// starting rock player when a move file was clicked. we dont have an activity then,
// but the package exits as soon as back is hit. so we can ignore the activity
// in this case
if(process==null)
return false;
RunningAppProcessInfo currentFg=getForegroundApp();
ComponentName currentActivity=getActivityForApp(currentFg);
if(currentFg!=null && currentFg.processName.equals(process.processName) &&
(activity==null || currentActivity.compareTo(activity)==0))
return true;
Slog.i(TAG, "isStillActive returns false - CallerProcess: " + process.processName + " CurrentProcess: "
+ (currentFg==null ? "null" : currentFg.processName) + " CallerActivity:" + (activity==null ? "null" : activity.toString())
+ " CurrentActivity: " + (currentActivity==null ? "null" : currentActivity.toString()));
return false;
}
private boolean isRunningService(String processname){
if(processname==null || processname.isEmpty())
return false;
RunningServiceInfo service;
if(mActivityManager==null)
mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
List <RunningServiceInfo> l = mActivityManager.getRunningServices(9999);
Iterator <RunningServiceInfo> i = l.iterator();
while(i.hasNext()){
service = i.next();
if(service.process.equals(processname))
return true;
}
return false;
}
回答by Friedrich Bhaer
Try the following code:
试试下面的代码:
ActivityManager activityManager = (ActivityManager) newContext.getSystemService( Context.ACTIVITY_SERVICE );
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for(RunningAppProcessInfo appProcess : appProcesses){
if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
Log.i("Foreground App", appProcess.processName);
}
}
Process name is the package name of the app running in foreground. Compare it to the package name of your application. If it is the same then your application is running on foreground.
进程名称是在前台运行的应用程序的包名称。将其与应用程序的包名称进行比较。如果相同,则您的应用程序正在前台运行。
I hope this answers your question.
我希望这回答了你的问题。
回答by Suman
From lollipop onwards this got changed. Please find below code, before that user has to go Settings -> Security -> (Scroll down to last) Apps with usage access -> Give the permissions to our app
从棒棒糖开始,这种情况发生了变化。请找到以下代码,然后该用户必须转到设置 -> 安全 ->(向下滚动到最后)具有使用权限的应用程序 -> 授予我们应用程序的权限
private void printForegroundTask() {
String currentApp = "NULL";
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
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();
}
}
} else {
ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> tasks = am.getRunningAppProcesses();
currentApp = tasks.get(0).processName;
}
Log.e(TAG, "Current App in foreground is: " + currentApp);
}
回答by Sarthak Mittal
For cases when we need to check from our own service/background-thread whether our app is in foreground or not. This is how I implemented it, and it works fine for me:
对于需要从我们自己的服务/后台线程检查我们的应用程序是否在前台的情况。这就是我实现它的方式,它对我来说很好用:
public class TestApplication extends Application implements Application.ActivityLifecycleCallbacks {
public static WeakReference<Activity> foregroundActivityRef = null;
@Override
public void onActivityStarted(Activity activity) {
foregroundActivityRef = new WeakReference<>(activity);
}
@Override
public void onActivityStopped(Activity activity) {
if (foregroundActivityRef != null && foregroundActivityRef.get() == activity) {
foregroundActivityRef = null;
}
}
// IMPLEMENT OTHER CALLBACK METHODS
}
Now to check from other classes, whether app is in foreground or not, simply call:
现在要从其他类检查应用程序是否在前台,只需调用:
if(TestApplication.foregroundActivityRef!=null){
// APP IS IN FOREGROUND!
// We can also get the activity that is currently visible!
}
Update (as pointed out by SHS):
更新(如SHS所指出的):
Do not forget to register for the callbacks in your Application class's onCreate
method.
不要忘记在 Application 类的onCreate
方法中注册回调。
@Override
public void onCreate() {
...
registerActivityLifecycleCallbacks(this);
}
回答by rvalerio
In order to determine the foreground application, you can use for detecting the foreground app, you can use https://github.com/ricvalerio/foregroundappchecker. It uses different methods depending on the android version of the device.
为了确定前台应用程序,您可以使用检测前台应用程序,您可以使用https://github.com/ricvalerio/foregroundappchecker。它根据设备的 android 版本使用不同的方法。
As for the service, the repo also provides the code you need for it. Essentially, let android studio create the service for you, and then onCreate add the snippet that uses the appChecker. You will need to request permission however.
至于服务,repo 还提供了你需要的代码。本质上,让 android studio 为您创建服务,然后 onCreate 添加使用 appChecker 的代码段。但是,您需要请求许可。
回答by Ayaz Alifov
Taking into account that getRunningTasks()
is deprecated and getRunningAppProcesses()
is not reliable, I came to decision to combine 2 approaches mentioned in StackOverflow:
考虑到getRunningTasks()
已弃用getRunningAppProcesses()
且不可靠,我决定结合 StackOverflow 中提到的 2 种方法:
private boolean isAppInForeground(Context context)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
{
ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();
return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase());
}
else
{
ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
ActivityManager.getMyMemoryState(appProcessInfo);
if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
{
return true;
}
KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
// App is foreground, but screen is locked, so show notification
return km.inKeyguardRestrictedInputMode();
}
}
回答by Charles Duffy
The ActivityManagerclass is the appropriate tool to see which processes are running.
该ActivityManager类是适当的工具,看看哪些进程正在运行。
To run in the background, you typically want to use a Service.
要在后台运行,您通常希望使用Service。
回答by NakulSargur
This worked for me. But it gives only the main menu name. That is if user has opened Settings --> Bluetooth --> Device Name screen, RunningAppProcessInfo calls it as just Settings. Not able to drill down furthur
这对我有用。但它只给出了主菜单名称。也就是说,如果用户打开了设置 --> 蓝牙 --> 设备名称屏幕,RunningAppProcessInfo 将其称为设置。无法进一步深入
ActivityManager activityManager = (ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE );
PackageManager pm = context.getPackageManager();
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for(RunningAppProcessInfo appProcess : appProcesses) {
if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(appProcess.processName, PackageManager.GET_META_DATA));
Log.i("Foreground App", "package: " + appProcess.processName + " App: " + c.toString());
}
}
回答by rubmz
In lollipop and up:
在棒棒糖及以上:
Add to mainfest:
添加到mainfest:
<uses-permission android:name="android.permission.GET_TASKS" />
And do something like this:
并做这样的事情:
if( mTaskId < 0 )
{
List<AppTask> tasks = mActivityManager.getAppTasks();
if( tasks.size() > 0 )
mTaskId = tasks.get( 0 ).getTaskInfo().id;
}