Android 12系统源码_页面管理(四)获取系统当前最上层的Activity信息

本文主要是介绍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信息的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/666177

相关文章

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

SpringBoot 获取请求参数的常用注解及用法

《SpringBoot获取请求参数的常用注解及用法》SpringBoot通过@RequestParam、@PathVariable等注解支持从HTTP请求中获取参数,涵盖查询、路径、请求体、头、C... 目录SpringBoot 提供了多种注解来方便地从 HTTP 请求中获取参数以下是主要的注解及其用法:1

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

基于Python实现自动化邮件发送系统的完整指南

《基于Python实现自动化邮件发送系统的完整指南》在现代软件开发和自动化流程中,邮件通知是一个常见且实用的功能,无论是用于发送报告、告警信息还是用户提醒,通过Python实现自动化的邮件发送功能都能... 目录一、前言:二、项目概述三、配置文件 `.env` 解析四、代码结构解析1. 导入模块2. 加载环

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象