最近有个需求,长链接接收到某个特定消息后,需要先关闭其他页面,然后跳转到指定页面。
这需求不难,清Activity栈而已,对Android有点点了解都能做。不过直接操作Activity栈的权限android.permission.GET_TASKS ,目前已经被废弃了,所以只能用其他办法实现这个需求。
正经方案:App内自己创建一个 Stack,然后在application的生命周期回掉中记录,或者在BaseActivity中记录,然后进行操作。
歪门邪道:反射获取ActivityStack,然后finish所有非首页的 Activity。
private static List<Activity> getActivitiesByApplication(Application application) {
List<Activity> list = new ArrayList<>();
try {
Class<Application> applicationClass = Application.class;
Field mLoadedApkField = applicationClass.getDeclaredField("mLoadedApk");
mLoadedApkField.setAccessible(true);
Object mLoadedApk = mLoadedApkField.get(application);
Class<?> mLoadedApkClass = mLoadedApk.getClass();
Field mActivityThreadField = mLoadedApkClass.getDeclaredField("mActivityThread");
mActivityThreadField.setAccessible(true);
Object mActivityThread = mActivityThreadField.get(mLoadedApk);
Class<?> mActivityThreadClass = mActivityThread.getClass();
Field mActivitiesField = mActivityThreadClass.getDeclaredField("mActivities");
mActivitiesField.setAccessible(true);
Object mActivities = mActivitiesField.get(mActivityThread);
// 注意这里一定写成Map,低版本这里用的是HashMap,高版本用的是ArrayMap
if (mActivities instanceof Map) {
@SuppressWarnings("unchecked")
Map<Object, Object> arrayMap = (Map<Object, Object>) mActivities;
for (Map.Entry<Object, Object> entry : arrayMap.entrySet()) {
Object value = entry.getValue();
Class<?> activityClientRecordClass = value.getClass();
Field activityField = activityClientRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
Object o = activityField.get(value);
list.add((Activity) o);
}
}
} catch (Exception e) {
e.printStackTrace();
list = null;
}
return list;
}
参考博客:利用反射拿到Android的整个Activity栈。--Jerry2015
这种方案,在没有修改主工程module,也没有添加其他脚手架的情况下,临时性解决了问题,但是很明显不是最佳的解决方案。
所以今天记录一下这个问题,然后。。。
//TODO 优化