声明:本文为Dujinyang CSDN原创投稿文章,未经许可,禁止任何形式的转载。
最近5.0\6.0\7.0 安卓系统都陆续上岗了,兼容性和代码更新是个很头疼的问题,这次我们来说下TASK的基础和API 4.4以上解决方法;
* 必要权限:
<uses-permission android:name = “android.permission.GET_TASKS”/>
* 涉及的TASK()方法:
1. 当前应用是否为前台task
2. 当前应用是否为后台task
3. 当前activity是否是Top Activity
4. 获取nums相应数量的activity
* 遇到问题:
android5.0新特性不能获取 getRunningTask() ?
* 有几个解决方案:
1. 手动打开,让用户授权实现;
2. 代码UsageStatsManager解决,Android官方提供的
3. 用ADB进入手机查看(对于开发只能是辅助功能)
下面我们就来仔细的深入吧~
首先我们先来看下调用Task相关的方法和使用:
1. 当前应用是否为前台task
* 判断当前应用的是否为前台task * @author dujinyang * @param context * @return */ public static boolean isAppForgroud(Context context) { if (context != null) { String packName = context.getPackageName(); List<RunningTaskInfo> rTasks = getRunningTask(context, 1); RunningTaskInfo task = rTasks.get(0); return packName.equalsIgnoreCase(task.topActivity.getPackageName()); } return false; }
2. 当前应用是否为后台task
/ * 判断当前应用的是否为后台task * @author dujinyang * @param context * @param packName * @return */ public static boolean isAppBackgroud(Context context) { if (context != null) { String packName = context.getPackageName(); List<RunningTaskInfo> rTasks = getRunningTask(context, 1); RunningTaskInfo task = rTasks.get(0); return !packName.equalsIgnoreCase(task.topActivity.getPackageName()); } return false; }
3. 当前activity是否是Top Activity
/ * 判断当前的activity是否为top activity @author dujinyang * @param context * @param className * @return */ public static boolean isTopActivity(Context context, String className) { List<RunningTaskInfo> rTasks = getRunningTask(context, 1); for (RunningTaskInfo task : rTasks) { Log.d("SystemUtils", "isTopActivity:" + task.topActivity.getClassName() + "|" + className); if (task.topActivity.getClassName().equals(className)) { return true; } } return false; }
4. 获取nums相应数量的activity
public static List<RunningTaskInfo> getRunningTask(Context context, int num) { if (context != null) { ActivityManager am = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE); List<RunningTaskInfo> rTasks = am.getRunningTasks(1); return rTasks; } return null; }
然后问题出现了:~~~~(>_<)~~~~
在android 5.0 版本后 获取栈顶应用的方法 getRunningTask方法被google给屏蔽掉了!
在5.0之前获取的方法是:API (4.4以下)
/** * 获取activity */ protected void getTastInfos() { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); RunningTaskInfo info = manager.getRunningTasks(1).get(0); String shortClassName = info.topActivity.getShortClassName(); //类名 String className = info.topActivity.getClassName(); //完整类名 String packageName = info.topActivity.getPackageName(); //包名 Log.e("test","YYSDK className:"+className); Log.e("test","YYSDK shortClassName :"+shortClassName); Log.e("test","YYSDK packageName:"+packageName); }
为啥?
原因是Android 5.0在API权限上作了修改:
Android L, Google has disabled getRunningTasks. Now it can only return own apps task and the home launcher.
处理方法:
解决办法之一:
其实就是使用UsageStatsManager获取,但是这种获取方法需要用户在手机上赋予APP权限才可以使用,就是在安全-高级-有权查看使用情况的应用在这个模块中勾选上指定APP就可以获取到栈顶的应用名。那么现在问题来了,如何调用系统提供的常量打开“有权查看使用权限的应用”界面。
其实是使用:
Settings.ACTION_USAGE_ACCESS_SETTINGS
根据此常量打开设置--“有权查看使用权限的应用”,不过在很多系统中被去掉了,如:小米、魅族等~
下面上代码:
判断当前设备中有没有“有权查看使用权限的应用”这个选项
private boolean isNoOptions() { PackageManager packageManager = getApplicationContext().getPackageManager(); Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); List<ResolveInfo> list = packageManager.queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; }
判断调用该设备中“有权查看使用权限的应用”这个选项的APP有没有打开
private boolean isNoSwitch() { long dujinyang = System.currentTimeMillis(); UsageStatsManager usageStatsManager = (UsageStatsManager) getApplicationContext().getSystemService("usagestats"); ist<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats( UsageStatsManager.INTERVAL_BEST, 0, dujinyang ); if (queryUsageStats == null || queryUsageStats.isEmpty()) { return false; } return true; }
buttonViews.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent( Settings.ACTION_USAGE_ACCESS_SETTINGS); startActivity(intent); } });
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
解决办法之二:
参考文档:http://stackoverflow.com/questions/24625936/getrunningtasks-doesnt-work-in-android-l
上面的stackoverflow网址里面还有其它解决方法;
public void getTopActivtyFromLolipopOnwards(){
String topPackageName ;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager mUsageStatsManager = (UsageStatsManager)getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
// We get usage stats for the last 10 seconds
List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*10, time);
// Sort the stats by the last time used
if(stats != null) {
SortedMap<Long,UsageStats> mySortedMap = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats) {
mySortedMap.put(usageStats.getLastTimeUsed(),usageStats);
}
if(mySortedMap != null && !mySortedMap.isEmpty()) {
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
Log.e("TopPackage Name",topPackageName);
}
}
}
}
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
解决办法之三:用ADB进入手机查看(对于开发只能是辅助功能)
如果是代码层开发者可以忽略以下内容~
Android还为开发者提供了adb(Android Debug Bridge),这是非常强大的调试工具。最常用的自然是logcat来显示日志记录。另外一个很强大的指令就是这里要提到的dumpsys。
dumpsys
还可以添加不同的参数来指示需要输出哪一类Service的信息。对于本文提到的内容,需要查看的就是activity
,指令就是:
adb shell dumpsys activity
输入上述指令,就能得到关于设备非常长的一段讯息,单是也能清晰看出它们比较详细的分类:
ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes) Process LRU list (sorted by oom_adj, 28 total, non-act at 3, non-svc at 3): PERS #27: sys F/ /P trm: 0 605:system/1000 (fixed) ... ... ... ...
每一个类别都有一个括号内容,给出了更加详细的指令来查看该类别下更多具体内容。因此再来尝试指令:
db shell dumpsys activity activities
整个log显示了当前所有在运行的任务栈,它们的id
分别是什么。对于每个Task,也有Activity数量等信息,同时也列出了其中的Activity列表,并且对于每个Activity也有比较详细的描述,比如启动它的Intent的内容。
如果觉得内容过多,只想看看栈的内容,也可以直接跳到”Running activities (most recent first)”那部分,比较简洁而又明了的列出了栈中得Activity列表,就能知道当按下返回键的时候会应该会回到哪个Activity以后是要退出程序。
对于”Running activitie”s的内容在dumpsys activity
中就有,并不需要dumpsys activity activities
,也可以用下边的指令来限制仅输出”Running activities”列表:
adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'
缺点
很明显的看出,使用adb shell
的相对于之前的方式的明显好处就是不需要添加额外的代码,而且任务栈的信息也更加详尽。但是同样的它只能输出Activity的类名,对于具体属性没有记录。
adb shell
对于调试Android程序有很多的帮助,可惜对于adb指令都没有比较全面详细而又系统的教程。只能靠在实践中慢慢摸索,从网上零星介绍中获得。
_____________________________________________________________________________________________________________________