[Android] Android获取当前顶部Activity名方法历史版本汇总
在做一个显示当前顶部activity名和包名的ToolApp时遇到的问题。
在Android5.0之前,获取top Activity方法非常简单。直接使用getRunningTasks方法即可。
//getRunningTasks() is deprecated since API Level 21 (Android 5.0) List localList = manager.getRunningTasks(1); ActivityManager.RunningTaskInfo localRunningTaskInfo = (ActivityManager.RunningTaskInfo)localList.get(0); info.packageName = localRunningTaskInfo.topActivity.getPackageName(); info.topActivityName = localRunningTaskInfo.topActivity.getClassName();
但是这个方法到了5.0就被Android因安全原因ban掉了。这之后使用该方法只能获取到Laucher的信息了。
后来有人找出了ActivityManger的一个方法:
private String getLollipopRecentTask() { final int PROCESS_STATE_TOP = 2; try { Field processStateField = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState"); List processes = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses(); for (ActivityManager.RunningAppProcessInfo process : processes) { if (process.importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && process.importanceReasonCode == 0) { int state = processStateField.getInt(process); if (state == PROCESS_STATE_TOP) { String[] packname = process.pkgList; return packname[0]; } } } } catch (Exception e) { throw new RuntimeException(e); } return ""; }
然而仅仅过了一个Android OS版本,这个也无法生效了。 所以有人找出了这样的方法:
public static void getInfo() { if (Build.VERSION.SDK_INT >= 21) { if (mUsageStatsManager != null) { long now = System.currentTimeMillis(); // get app data during 60s List stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, now - 60 * 1000, now); // get present app if ((stats != null) && (!stats.isEmpty())) { int j = 0; for (int i = 0; i < stats.size(); i++) { if (stats.get(i).getLastTimeUsed() > stats.get(j).getLastTimeUsed()) { j = i; } } topPackageName = stats.get(j).getPackageName(); topActivityName = ""; } } }
通过UsageStatsManager获取最近一段时间的使用数据,找到最后一次被使用的信息。但是这个方法只能获取到Package名,得不到Activity的名字。
后来在StackOverFlow上看到了这样的做法:(https://stackoverflow.com/questions/31980976/get-top-activity-name-in-android-l)
while (true) { final long INTERVAL = 1000; final long end = System.currentTimeMillis(); final long begin = end - INTERVAL; final UsageEvents usageEvents = manager.queryEvents(begin, end); while (usageEvents.hasNextEvent()) { UsageEvents.Event event = new UsageEvents.Event(); usageEvents.getNextEvent(event); if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) { Log.d("event", "timestamp : " + event.getTimeStamp()); Log.d("event", "package name : " + event.getPackageName()); Log.d("event", "class name : " + event.getClassName()); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }}
似乎可以生效没有试过。但是需要死循环不停地读,没有办法动态地监听,吃相有些难看,不够优雅。
最后通过翻阅资料,找到了一个极佳的方法,就是借助Accessibility辅助功能来实现。
public class WindowChangeDetectingService extends AccessibilityService { private static final String TAG = "WCDService"; @Override public void onCreate() { Log.d(TAG, "onCreate"); } @Override public void onDestroy() { Log.d(TAG, "onDestroy"); } @Override protected void onServiceConnected() { Log.d(TAG, "onServiceConnected"); super.onServiceConnected(); // Configure these here for compatibility with API 13 and below. AccessibilityServiceInfo config = new AccessibilityServiceInfo(); config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; // Just in case this helps config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; setServiceInfo(config); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { Log.d(TAG, "onAccessibilityEvent"); if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { if (event.getPackageName() != null && event.getClassName() != null) { ComponentName componentName = new ComponentName( event.getPackageName().toString(), event.getClassName().toString() ); ActivityInfo activityInfo = tryGetActivity(componentName); boolean isActivity = activityInfo != null; if (isActivity) { Log.d(TAG, "CurentActivity " + componentName.flattenToShortString()); ActivityManagerUtils.topActivityName = componentName.flattenToShortString(); ActivityManagerUtils.topPackageName = event.getPackageName().toString(); } } } } private ActivityInfo tryGetActivity(ComponentName componentName) { try { return getPackageManager().getActivityInfo(componentName, 0); } catch (PackageManager.NameNotFoundException e) { return null; } } @Override public void onInterrupt() {}}
需要一个继承Accessbility的Service,在它的onAccessbilityEvent回调方法里监听到窗口状态改变的事件,从中获取Activity的信息。
需要在AndroidManifest里面配置:
<?xml version="1.0" encoding="utf-8"?>
这个Service不需要自己手动启动,只要在手机的Setiings Accessbility里面打开注册了这个Service的APP对应的Accessbility的功能,这个Service就会自动启动。
附:我自己做的显示当前页面Activity信息的APP,CurrentActivity。
GitHub: https://github.com/Haocxx/CurrentActivity
更多相关文章
- Android兼容性问题 -- SparseArray.clone()方法异常
- Android Studio:xxx is not an enclosing class 错误的解决方法
- Android logcat内核信息
- 【Android】Android 发送短信和打电话的方法
- Android中AutoCompleteTextView的特殊使用方法
- Android 解决fragment replace方法低效的问题
- Android中WARNING: Application does not specify an API level
- 使用android中的handler延迟执行方法