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…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
