Android 12系统源码_页面管理(四)获取系统当前最上层的Activity信息
前言
很多应用开发人员,在日常开发过程中,经常会遇到一些需求,例如需要知道当前最上层的Activity是哪个,并结合这个Activity的名称来完成一些特定场景的需求。最简单的方法,是在创建Activity的时候将该Actvity存储到一个集合中,而当Activity销毁的时候,再将该Activity从集合中移除,这种方案虽然能够获取自己应用当前最上层的Activity是那个,但却无法获取除了自己应用以外的其他场景。犹豫谷歌为系统开发提供了特定的API,作为系统开发人员,我们完全可以通过这些API实时获取当前最上层的Activity信息,并将这些信息同步给系统应用。本篇文章我们将会结合Android12的系统源码,来探讨一下如何通过系统内部API实时获取当前系统最上层的Activity的信息,以及如何实时监听当前系统Activity栈信息的变化。
一、获取最上层的根任务信息
1、根任务是指包含一个或多个 Activity 的任务,并且没有父任务,根任务通常是由用户启动的应用程序或系统应用程序的主要任务。
在 Android 12 中,我们可以通过以下代码获取最上层的根任务信息。
IActivityManager ams = ActivityManager.getService(); //获取ActivityManagerService服务对象
List<ActivityManager.RunningTaskInfo> runningTasks = mAm.getTasks(1);;//调用getAllRootTaskInfos方法
首先调用ActivityManager的getService方法获取ActivityManagerService服务对象,然后调用该服务对象的getTasks(int maxNum) 方法,该方法会返回一个指定数量包含所有根任务信息的列表,每个根任务都有其任务 ID、根 Activity 的信息以及与之关联的其他活动堆栈。
2、来看下和RunningTaskInfo类相关的代码。
base/core/java/android/app/ActivityManager.java
public class ActivityManager {public static class RunningTaskInfo extends TaskInfo implements Parcelable {/*** 当前任务的唯一标识id* A unique identifier for this task.*/@Deprecatedpublic int id;/*** 当前任务状态的缩略图* Thumbnail representation of the task's current state.*/@Deprecatedpublic Bitmap thumbnail;/*** 当前任务的状态描述* Description of the task's current state.*/@Deprecatedpublic CharSequence description;/*** 当前任务中正在运行的Activity的数量* Number of activities that are currently running (not stopped and persisted) in this task.*/@Deprecatedpublic int numRunning;}
}
RunningTaskInfo类包含了当前任务对应的唯一标识ID、Bitmap类型的缩略图、状态描述以及该任务正运行的Activity的数量。
3、RunningTaskInfo继承自TaskInfo,继续来看下该类有哪些关键属性。
base/core/java/android/app/TaskInfo.java
public class TaskInfo {private static final String TAG = "TaskInfo";/*** 当前任务对应的用户id * The id of the user the task was running as if this is a leaf task. The id of the current* running user of the system otherwise.* @hide*/@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)public int userId;/*** 任务id* The identifier for this task.*/public int taskId;/*** 此任务中是否有正在运行的Activity* Whether or not this task has any running activities.*/public boolean isRunning;/*** 启动当前任务的Intent* The base intent of the task (generally the intent that launched the task). This intent can* be used to relaunch the task (if it is no longer running) or brought to the front if it is.*/@NonNullpublic Intent baseIntent;/*** The component of the first activity in the task, can be considered the "application" of this* task.*/@Nullablepublic ComponentName baseActivity;/*** 当前任务对应的Activity栈中的最上层正在显示的activity* The component of the top activity in the task, currently showing to the user.*/@Nullablepublic ComponentName topActivity;/*** The component of the target activity if this task was started from an activity alias.* Otherwise, this is null.*/@Nullablepublic ComponentName origActivity;/*** The component of the activity that started this task (may be the component of the activity* alias).* @hide*/@Nullablepublic ComponentName realActivity;/*** The number of activities in this task (including running).*/public int numActivities;/*** The last time this task was active since boot (including time spent in sleep).* @hide*/@UnsupportedAppUsagepublic long lastActiveTime;/*** 当前任务对应的屏幕设备id* The id of the display this task is associated with.* @hide*/public int displayId;/*** The feature id of {@link com.android.server.wm.TaskDisplayArea} this task is associated with.* @hide*/public int displayAreaFeatureId = FEATURE_UNDEFINED;/*** The recent activity values for the highest activity in the stack to have set the values.* {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.*/@Nullablepublic ActivityManager.TaskDescription taskDescription;/*** The locusId of the task.* @hide*/@Nullablepublic LocusId mTopActivityLocusId;/*** 当前任务是否支持分屏* True if the task can go in the split-screen primary stack.* @hide*/@UnsupportedAppUsagepublic boolean supportsSplitScreenMultiWindow;/*** 当前任务是否支持多窗口* Whether this task supports multi windowing modes based on the device settings and the* root activity resizability and configuration.* @hide*/public boolean supportsMultiWindow;/*** The resize mode of the task. See {@link ActivityInfo#resizeMode}.* @hide*/@UnsupportedAppUsagepublic int resizeMode;/*** The current configuration of the task.* @hide*/@NonNull@UnsupportedAppUsagepublic final Configuration configuration = new Configuration();/*** Used as an opaque identifier for this task.* @hide*/@NonNullpublic WindowContainerToken token;/*** 用于控制画中画模式的参数类* The PictureInPictureParams for the Task, if set.* @hide*/@Nullablepublic PictureInPictureParams pictureInPictureParams;/*** The {@link Rect} copied from {@link DisplayCutout#getSafeInsets()} if the cutout is not of* (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS),* {@code null} otherwise.* @hide*/@Nullablepublic Rect displayCutoutInsets;/*** 当前任务最上层Activity的类型* The activity type of the top activity in this task.* @hide*/public @WindowConfiguration.ActivityType int topActivityType;/*** The {@link ActivityInfo} of the top activity in this task.* @hide*/@Nullablepublic ActivityInfo topActivityInfo;/*** Whether the direct top activity is in size compat mode on foreground.* @hide*/public boolean topActivityInSizeCompat;/*** Whether this task is resizable. Unlike {@link #resizeMode} (which is what the top activity* supports), this is what the system actually uses for resizability based on other policy and* developer options.* @hide*/public boolean isResizeable;/*** Relative position of the task's top left corner in the parent container.* @hide*/public Point positionInParent;/*** The launch cookies associated with activities in this task if any.* @see ActivityOptions#setLaunchCookie(IBinder)* @hide*/public ArrayList<IBinder> launchCookies = new ArrayList<>();/*** The identifier of the parent task that is created by organizer, otherwise* {@link ActivityTaskManager#INVALID_TASK_ID}.* @hide*/public int parentTaskId;/*** 当前任务是否持有焦点* Whether this task is focused.* @hide*/public boolean isFocused;/*** 当前任务是否可见* Whether this task is visible.* @hide*/public boolean isVisible;/*** Whether this task is sleeping due to sleeping display.* @hide*/public boolean isSleeping;}
TaskInfo类中也包含了很多对于当前任务至关重要的信息:任务对应的用户id、任务id、任务中是否有运行的Activity、启动任务的Intent、任务对应的Activity栈最上层Activity,对应的屏幕设备id、任务是否支持分屏、任务是否支持多窗口、用于控制画中画模式的参数类、任务是否持有焦点、任务是否可见等。
二、实时监听Activity栈信息变化。
1、我们主要是通过调用ActivityManagerService的相关方法来实时监听Activity对应的任务栈的变化的,具体可以参考以下代码。
//获取ActivityManagerService的实例对象IActivityManager am = ActivityManager.getService();//调用registerTaskStackListener方法,注册监听任务栈变化的回调对象am.registerTaskStackListener(new TaskStackListener() {@Overridepublic void onTaskStackChanged() throws RemoteException {final ActivityManager.RunningTaskInfo runningTask;try {//List<ActivityManager.RunningTaskInfo> runningTasks = mAm.getTasks(1);if (runningTasks == null) {return;}runningTask = runningTasks.get(0);} catch (RemoteException e) {e.printStackTrace();return;}if (runningTask == null) {return;}int displayId = runningTask.displayId;if (INVALID_DISPLAY != displayId && runningTask.topActivity != null) {String key = "display_" + displayId + "_top_activity";String packageName = runningTask.topActivity.getPackageName();String activityName = runningTask.topActivity.getClassName();String value = packageName + "/" + activityName;boolean isUpdate = !value.equals(mHashMapDisplayTopActivity.get(key));if (isUpdate) {Log.d(TAG, "updateTasks: key = " + key + " value = " + value);mHashMapDisplayTopActivity.put(key, value);}} }});;
对以上代码做个简单介绍:
- 我们可以通过调用ActivityManagerService的registerTaskStackListener方法注册回调对象,实时监听当前任务栈的变化。
- 继续调用ActivityManagerService的getTasks方法,获取当前正在运行的所有任务,该方法返回一个类型为RunningTaskInfo的集合,关于RunningTaskInfo这个类,前面我们已经做过简单介绍了。
- 最后结合RunningTaskInfo的相关属性,可以成功获取到当前系统中每个屏幕设备对应的最上层的Activity的包名和组件名称。
三、异常处理
不过在进行实测的时候发现,通过调用registerTaskStackListener方法注册的回调方法,有一定概率在页面发生切换的时候不会进行回调,比如应用异常崩溃,应用ANR被强制关闭等特殊情况,这个字段回调方法并没有执行,这就需要我们在这些事件发生的时候,通知AMS让其进行回调事件的调用。
相关文章:
Android 12系统源码_页面管理(四)获取系统当前最上层的Activity信息
前言 很多应用开发人员,在日常开发过程中,经常会遇到一些需求,例如需要知道当前最上层的Activity是哪个,并结合这个Activity的名称来完成一些特定场景的需求。最简单的方法,是在创建Activity的时候将该Actvity存储到一…...
RK3588开发板Ubuntu与开发板使用U盘互传
1 将 U 盘(U 盘的格式必须为 FAT32 格式,大小在 32G 以下)插到开发板的 usb 接口,串口打印信息如下所示,U 盘的设备节点是/dev/sdb4。U 盘的设备节点不是固定的,根据实际情况来查看设备节点。 2 输入以下命令挂载 U 盘,…...
【BUG】golang gorm导入数据库报错 “unexpected type clause.Expr“
帮同事排查一个gorm导入数据报错的问题 事发现场 ck sql CREATE TABLE ods_api.t_sms_jg_msg_callback_dis (app_key String DEFAULT COMMENT 应用标识,callback_type Int32 DEFAULT 0 COMMENT 0送达,1回执,channel Int32 DEFAULT 0 COMMENT uid下发的渠道,mode…...
TCP/IP网络模型
大家好我是苏麟 , 今天聊聊TCP/IP四层网络模型 . 资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 应用层 最上层的,也是我们能直接接触到的就是应用层(Application Layer),我们电脑或手机使用的应用软件都…...
github连不上
github连不上 错误提示解决方案steam 采用Hosts加速 错误提示 fatal: unable to access ‘https://github.com/Ada-design/qianduan.git/’: Failed to connect to github.com port 443 after 21073 ms: Couldn’t connect to server 解决方案 下载steam https://steampp.ne…...
Excel计算表达式的值
Excel如何求解表达式 其中第三种方法最简单,通过剪贴板实现 如,单元格A1中输入了 12345 然后在A2输入 “”&A1 然后复制A2,打开剪贴板,点击刚才复制的内容,就会在A2显示计算结果...
26元/月起!腾讯云一键自动搭建4核16G幻兽帕鲁服务器
腾讯云无需任何配置自动搭建幻兽帕鲁游戏联机服务器,游戏24小时在线,4核16G游戏联机服务器低至26元/月起,新手小白也能一键搭建属于自己的幻兽帕鲁游戏联机服务器! 第一步:购买游戏联机服务器 购买入口:htt…...
【C++游戏开发-01】推箱子
C游戏开发 文章目录 C游戏开发[TOC](文章目录) 前言一、逻辑分析1.1地图实现1.2人物的移动1.2.1小人移动1.2.2其他移动 1.3墙壁的碰撞1.4箱子的推动1.4.1什么时候推箱子1.4.2什么情况可以推箱子 1.5胜利的判断1.6卡关的处理1.7关卡的切换 二、DEMO代码2.1游戏框架2.2各功能函数…...
【lesson26】学习MySQL事务前的基础知识
文章目录 CURD不加控制,会有什么问题?CURD满足什么属性,能解决上述问题?什么是事务?为什么会出现事务事务的版本支持 CURD不加控制,会有什么问题? CURD满足什么属性,能解决上述问题&…...
持续积累分享金融知识
持续积累分享金融知识 一、什么是两融余额?二、什么是量化?三、散户可以进行量化投资么? 一、什么是两融余额? 两融余额是指投资者在融资买入和融券卖出交易中,通过向券商借入资金或证券进行交易,并且在交…...
网络协议 UDP协议
网络协议 UDP协议 在之前的文章中有对UDP协议套接字的使用进行讲解,本文主要对UDP协议进行一些理论补充。 文章目录 网络协议 UDP协议1. 概念2. UDP协议格式2.1 数据报长度2.2 校验和/检验和2.2.1 CRC校验2.2.2 MD5算法 1. 概念 UDP,即User Datagram P…...
爬虫笔记(三):实战qq登录
咳咳,再这样下去会进橘子叭hhhhhh 以及,这个我觉得大概率是成功的,因为测试了太多次,登录并且验证之后,qq提醒我要我修改密码才可以登录捏QAQ 1. selenium 有关selenium具体是啥,这里就不再赘述了&#x…...
又涨又跌 近期现货黄金价格波动怎么看?
踏入2024年一月的下旬,现货黄金价格可以说没了之前火热的状态,盘面上是又涨又跌。面对这样的行情,很多投资者不知道如何看了。下面我们就来讨论一下怎么把握近期的行情。 先区分走势类型。在现货黄金市场中有两种主要的走势类型,一…...
软件压力测试:探究其目的与重要性
随着软件应用在各行各业中的广泛应用,确保软件在高负载和极端条件下的稳定性变得至关重要。软件压力测试是一种验证系统在不同负载条件下的性能和稳定性的方法。本文将介绍软件压力测试的目的以及为什么它对软件开发和部署过程至关重要。 验证系统性能的极限&#x…...
Android.bp入门指南之浅析Android.bp文件
文章目录 Android.bp文件是什么?Android.bp的主要作用模块定义依赖关系构建规则模块属性插件支持模块的可配置性 为什么会引入Android.bp语法例子 Android.bp文件是什么? Android.bp 文件是 Android 构建系统(Android Build Systemÿ…...
2024年美赛 (D题ICM)| 湖流网络水位控制 |数学建模完整代码+建模过程全解全析
当大家面临着复杂的数学建模问题时,你是否曾经感到茫然无措?作为2022年美国大学生数学建模比赛的O奖得主,我为大家提供了一套优秀的解题思路,让你轻松应对各种难题。 让我们来看看美赛的D题! 完整内容可以在文章末尾领…...
安卓网格布局GridLayout
<?xml version"1.0" encoding"utf-8"?> <GridLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_width"match_parent"android:la…...
DHCP简介
定义 动态主机配置协议DHCP(Dynamic Host Configuration Protocol)是一种用于集中对用户IP地址进行动态管理和配置的技术。即使规模较小的网络,通过DHCP也可以使后续增加网络设备变得简单快捷。 DHCP是在BOOTP(BOOTstrap Protoc…...
Hadoop生态系统中一些关键组件的详细解析
1. Hadoop核心组件 HDFS(Hadoop Distributed File System): 分布式文件存储系统。提供高吞吐量的数据访问,非常适合用于大规模数据集。有高容错性,通过在多个节点间复制数据块来实现。 MapReduce: 一种编程模型,用于在…...
功能强大的开源数据中台系统 DataCap 2024.01.1 发布
推荐一套基于 SpringBoot 开发的简单、易用的开源权限管理平台,建议下载使用: https://github.com/devlive-community/authx 推荐一套为 Java 开发人员提供方便易用的 SDK 来与目前提供服务的的 Open AI 进行交互组件:https://github.com/devlive-commun…...
OpenClaw技能库自动化安全审计与生态分析平台构建指南
1. 项目概述:为OpenClaw技能库打造一个“体检中心” 如果你正在使用或关注OpenClaw这个开源的智能体技能库,那你可能和我有同样的感受:仓库里的技能越来越多,社区贡献非常活跃,这当然是好事。但随之而来的问题是&…...
Surge托管配置自动更新失效?手把手教你将普通.conf文件转为托管配置
Surge托管配置自动更新失效的终极解决方案 你是否曾经遇到过这样的困扰:从某个渠道获取的Surge配置文件明明标注了托管配置URL,却始终无法自动更新?这背后往往隐藏着一个容易被忽视的关键细节——文件头部的魔法注释#!MANAGED-CONFIG。本文将…...
别再死记硬背了!从‘区间选点’和‘区间不相交’两道题,彻底搞懂贪心算法的排序关键
贪心算法实战:从两道区间问题看排序策略的本质差异 很多学习算法的同学在初次接触贪心算法时,都会遇到一个共同的困惑:为什么有些问题要按照左端点排序,有些却要按照右端点排序?更让人抓狂的是,有时候两道题…...
可穿戴AI系统的低功耗设计与优化实践
1. 可穿戴情境AI系统的设计挑战与核心价值在智能眼镜等可穿戴设备上实现全天候运行的情境AI系统,面临着移动计算领域最严苛的设计约束。一套标准的Ray-Ban Meta智能眼镜重量约50克,其中电池重量仅占10克左右。按照当前锂离子电池300mWh/g的能量密度计算&…...
开源AI代理如何革新软件开发:核心架构与实战解析
1. 开源AI代理在软件开发中的价值图谱开源社区正在重塑软件开发的工作范式。过去半年里,GitHub上涌现出数百个标榜"自主AI代理"的项目仓库,它们通过代码生成、问题诊断、自动化测试等能力,正在将"AI结对编程"的概念推向新…...
ArcGIS Pro 拓扑编辑实战:用‘地图拓扑’功能批量修改共享边界的完整流程
ArcGIS Pro 拓扑编辑实战:用‘地图拓扑’功能高效处理共享边界的完整指南 当面对需要同时修改多个相邻面要素的共享边界时,GIS工程师常常陷入两难:手动逐个编辑不仅耗时耗力,还容易在相邻要素间产生缝隙或重叠。这正是ArcGIS Pro中…...
AI编程助手:告别重复造轮子
引言:重复造轮子的痛点开发者在编写脚本时经常面临重复性工作,如文件操作、API调用模板等。手动编写不仅效率低,还容易引入错误。自动化脚本生成的优势效率提升:减少手动编码时间,快速生成基础代码框架。错误减少&…...
980 元入局!中小企业 AI 搜索获客轻量化方案
中小企业的线上获客,始终绕不开三大痛点:获客成本高企、专业技术门槛高、试错风险大。传统 SEM 投放单次点击成本动辄数十元,SEO 优化周期长达数月,而 AI 搜索时代的流量红利,又因技术壁垒难以触达。对于中小企业而言&…...
嵌入式事件驱动框架zeptoclaw:轻量级任务调度与协作式编程实践
1. 项目概述:一个为嵌入式与边缘计算而生的轻量级控制框架最近在折腾一些嵌入式项目,尤其是基于ESP32、树莓派Pico这类资源受限的MCU(微控制器)时,我总在寻找一个既轻量又灵活的控制框架。传统的实时操作系统ÿ…...
OpenClaw智能路由插件:基于任务类型自动分配AI模型
1. 项目概述:一个让AI“各司其职”的智能路由插件最近在折腾一个叫OpenClaw的AI网关项目,它本身是个挺有意思的东西,能把各种大模型(比如Claude、GPT、本地跑的Llama)统一管理起来,通过一个入口(…...
