PendingIntent概述

本文深入解析了PendingIntent的概念及其在通知栏应用中的作用。PendingIntent作为Android中的一种特殊Intent,用于延迟执行操作,提供了多种标志如FLAG_ONE_SHOT、FLAG_CANCEL_CURRENT和FLAG_UPDATE_CURRENT,以控制PendingIntent的行为。文章详细解释了这些标志如何影响通知栏的通知行为,如单次点击后的反应、新旧通知的处理以及Intent中Extra信息的更新。

一、定义

PendingIntent表示待定、等待、即将发生的意思。Intent表示的是立刻发生。

PendingIntent的主要方法:

int requestCode:表示请求码,跟intent是一样的。

int flags:常见的类型

FLAG_ONE_SHOT:当前描述的PendingIntent只能被使用一次,同类型的通知栏只能使用一次,后续的通知栏单击后将无法打开。

FLAG_NO_CREATE:当之前的PendingIntent不存在,则返回null(基本用不到)

FLAG_CANCEL_CURRENT:如果PendingIntent已存在,都会被cancel,然后系统创建一个新的PendingIntent。

FLAG_UPDATE_CURRENT:如果PendingIntent已经存在,则他们都会被更新,就是Intent中的extra都会被更新。

二、结合通知栏描描述

1.在Notification中有manager.notify(1,notification);如果第一个参数id是常量,多次调用notify方法,只会替换掉前面的notification。

如果参数id不为常量,PendingIntent才有意义。

FLAG_ONE_SHOT:当单机任何一条通知,其余的通知无法使用

FLAG_CANCEL_CURRENT:只有最新的通知可以打开,之前弹出的所有通知无法打开

FLAG_UPDATE_CURRENT:之前弹出的通知中的PendingIntent会被更新。

 

转载于:https://www.cnblogs.com/rookiechen/p/5427417.html

内容概要:本文围绕六自由度机械臂的人工神经网络(ANN)设计展开,重点研究了正向与逆向运动学求解、正向动力学控制以及基于拉格朗日-欧拉法推导逆向动力学方程,并通过Matlab代码实现相关算法。文章结合理论推导与仿真实践,利用人工神经网络对复杂的非线性关系进行建模与逼近,提升机械臂运动控制的精度与效率。同时涵盖了路径规划中的RRT算法与B样条优化方法,形成从运动学到动力学再到轨迹优化的完整技术链条。; 适合人群:具备一定机器人学、自动控制理论基础,熟悉Matlab编程,从事智能控制、机器人控制、运动学六自由度机械臂ANN人工神经网络设计:正向逆向运动学求解、正向动力学控制、拉格朗日-欧拉法推导逆向动力学方程(Matlab代码实现)建模等相关方向的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握机械臂正/逆运动学的数学建模与ANN求解方法;②理解拉格朗日-欧拉法在动力学建模中的应用;③实现基于神经网络的动力学补偿与高精度轨迹跟踪控制;④结合RRT与B样条完成平滑路径规划与优化。; 阅读建议:建议读者结合Matlab代码动手实践,先从运动学建模入手,逐步深入动力学分析与神经网络训练,注重理论推导与仿真实验的结合,以充分理解机械臂控制系统的设计流程与优化策略。
<think>我们正在处理一个高级需求:将一个Activity通过PendingIntent和TaskOrganizer启动到两个不同的分屏区域。这涉及到Android的分屏多窗口功能,以及如何使用TaskOrganizer(一个系统级API)来管理任务栈。同时,我们还需要使用PendingIntent,并且要注意FLAG_IMMUTABLE(因为从Android 12开始,PendingIntent必须指定可变性标志)。 核心目标:启动同一个Activity的两个实例到分屏的两个区域。 挑战: 1. 默认情况下,同一个Activity的多个实例会被视为同一个任务栈(除非使用不同的任务栈或启动模式)。 2. 分屏模式要求两个区域分别由两个不同的任务栈(Task)来填充。 3. 使用TaskOrganizer(属于android.window包)需要系统权限,通常只有系统应用(如SystemUI)可以使用。 因此,我们需要创建两个独立的任务(Task),每个任务中运行一个Activity实例,然后将这两个任务分别放置到分屏的两个区域。 步骤概述: 1. 创建两个独立的PendingIntent,每个PendingIntent用于启动目标Activity,但需要确保它们被放入不同的任务栈中。 2. 使用TaskOrganizer创建两个任务容器(TaskContainer),并将这两个容器设置为分屏模式。 3. 将每个PendingIntent与一个任务容器关联,这样当PendingIntent被触发时,Activity就会在指定的任务容器中启动。 注意:TaskOrganizer是隐藏API,普通应用无法直接使用。因此,此方案通常适用于系统应用或具有系统权限的应用(如定制ROM)。 详细步骤: 步骤1:创建两个不同的PendingIntent 为了将同一个Activity启动两次并放入不同的任务栈,我们需要为每个PendingIntent设置不同的任务栈标识。我们可以通过设置Intent的Flag和任务栈选项来实现。 关键点:使用`FLAG_ACTIVITY_MULTIPLE_TASK`和`FLAG_ACTIVITY_NEW_DOCUMENT`(或者`FLAG_ACTIVITY_NEW_TASK`)来创建独立的任务。 但是注意,从非Activity上下文启动Activity必须使用`FLAG_ACTIVITY_NEW_TASK`(参考引用[1])。 因此,我们可以这样构建Intent: ```java // 第一个Intent Intent intent1 = new Intent(context, TargetActivity.class); intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); // 可以添加额外数据区分实例 intent1.putExtra("region", "left"); // 第二个Intent Intent intent2 = new Intent(context, TargetActivity.class); intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); intent2.putExtra("region", "right"); ``` 然后创建两个PendingIntent,注意使用`FLAG_IMMUTABLE`(如果不需要修改PendingIntent的内容)或者`FLAG_MUTABLE`(如果需要修改): ```java PendingIntent pendingIntent1 = PendingIntent.getActivity(context, 0, intent1, PendingIntent.FLAG_IMMUTABLE); PendingIntent pendingIntent2 = PendingIntent.getActivity(context, 1, intent2, PendingIntent.FLAG_IMMUTABLE); // 注意requestCode不同,以区分两个PendingIntent ``` 步骤2:使用TaskOrganizer管理分屏容器 我们需要创建两个TaskContainer,分别对应分屏的两个区域。这需要系统权限。 首先,初始化TaskOrganizer: ```java TaskOrganizer taskOrganizer = new TaskOrganizer(); ``` 然后,创建两个SplitContainer,代表分屏的两个区域。这里需要指定两个区域的位置和大小(通常通过屏幕划分来确定)。 但是,TaskOrganizer的使用非常复杂,并且需要系统级支持。以下是一个简化的示例: 首先,我们需要监听任务栈的变化,并创建两个任务容器: ```java taskOrganizer.registerOrganizer(); // 创建两个任务容器,分别用于左右(或上下)两个区域 // 假设我们使用SplitController来管理分屏,但SplitController也是系统API // 这里我们直接使用TaskOrganizer的方法创建容器(实际上,TaskOrganizer并没有直接提供创建容器的方法,而是通过窗口管理器来创建) // 实际上,我们需要使用WindowContainerTransaction来创建分屏布局 WindowContainerTransaction wct = new WindowContainerTransaction(); // 创建两个任务栈,并设置它们为分屏模式 // 首先,获取当前活跃的任务栈(作为分屏的起点)或者创建一个新的任务栈 // 这里我们假设需要创建两个新的任务栈,并将它们并排显示 // 创建一个任务栈容器,用于左侧 Task leftTask = ...; // 如何创建?实际上,我们无法直接创建Task,而是通过启动Activity来创建,然后由系统分配Task。 // 因此,我们需要先启动Activity,然后获取其Task,再将其放入分屏容器。 另一种思路: 1. 使用TaskOrganizer的createRootTask方法创建两个根任务容器(RootTask),分别对应分屏的两个区域。 2. 然后,将这两个根任务容器设置为分屏布局。 但是,createRootTask是隐藏API,需要反射调用,并且需要系统权限。 步骤3:将PendingIntent启动的Activity放入指定的任务容器 我们需要在启动Activity之前,将目标任务容器(RootTask)的信息附加到Intent中。但是,标准Intent不支持直接指定任务容器。 替代方案:使用ActivityOptions的setLaunchTaskId,但要求目标Activity已经在一个独立的任务中,并且我们知道任务ID。 然而,我们还没有启动Activity,所以无法获取任务ID。因此,我们需要先创建两个空的任务容器(RootTask),然后在这两个容器中启动Activity。 具体步骤: 1. 创建两个根任务容器(RootTask)。 2. 获取每个根任务容器的任务ID。 3. 使用ActivityOptions将每个Activity启动到对应的任务容器中。 但是,PendingIntent并不直接支持ActivityOptions。我们可以使用PendingIntent.send()方法,它允许传入一个Bundle(包含ActivityOptions)作为参数。 代码示例: ```java // 创建第一个根任务容器 Bundle options1 = ActivityOptions.makeBasic().setLaunchTaskId(leftRootTask.getTaskId()).toBundle(); // 创建第二个根任务容器 Bundle options2 = ActivityOptions.makeBasic().setLaunchTaskId(rightRootTask.getTaskId()).toBundle(); // 发送PendingIntent try { pendingIntent1.send(context, 0, intent1, null, null, null, options1); pendingIntent2.send(context, 0, intent2, null, null, null, options2); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } ``` 问题:如何创建根任务容器(RootTask)? 在Android 10(API 29)及以上,可以使用TaskOrganizer.createRootTask方法(但这是系统API,普通应用无法调用)。 因此,我们需要在系统应用中执行以下操作: ```java // 创建左侧的根任务容器 Task leftRootTask = taskOrganizer.createRootTask(displayArea, 0); // 创建右侧的根任务容器 Task rightRootTask = taskOrganizer.createRootTask(displayArea, 0); // 然后,将这两个根任务容器设置为分屏模式 SplitController splitController = SplitController.getInstance(); SplitPair splitPair = new SplitPair.Builder(leftRootTask, rightRootTask) .setLayoutDirection(LAYOUT_DIRECTION_LEFT_TO_RIGHT) .build(); splitController.registerSplit(splitPair); ``` 注意:以上代码使用了大量系统隐藏API,需要系统签名权限。 步骤4:设置分屏布局 我们需要将两个根任务容器(RootTask)放置在分屏的两个区域。这可以通过WindowContainerTransaction设置两个容器的位置和大小来实现。 示例: ```java WindowContainerTransaction wct = new WindowContainerTransaction(); // 设置左侧容器占据屏幕左半部分 wct.setBounds(leftRootTask, new Rect(0, 0, screenWidth/2, screenHeight)); // 设置右侧容器占据屏幕右半部分 wct.setBounds(rightRootTask, new Rect(screenWidth/2, 0, screenWidth, screenHeight)); // 提交事务 taskOrganizer.applyTransaction(wct); ``` 然后,在这两个容器中启动Activity(通过PendingIntent.send并传入对应的ActivityOptions)。 总结: 由于涉及系统隐藏API,普通应用无法实现此功能。只有系统应用(如SystemUI)可以操作。因此,请确保你的应用具有系统权限。 完整代码结构(系统应用): 1. 初始化TaskOrganizer并注册。 2. 创建两个根任务容器(RootTask)。 3. 设置分屏布局(通过WindowContainerTransaction设置两个容器的位置和大小)。 4. 创建两个PendingIntent,每个Intent启动同一个Activity但带有不同的extra(可选)。 5. 使用ActivityOptions分别设置每个Activity启动到对应的根任务容器中。 6. 发送PendingIntent,并传入对应的ActivityOptions。 注意:由于Activity启动是异步的,所以需要确保在发送PendingIntent时,根任务容器已经创建并配置好。 另外,从Android 12开始,PendingIntent必须指定可变性标志(FLAG_IMMUTABLE或FLAG_MUTABLE)。我们这里使用了FLAG_IMMUTABLE,因为Intent不需要在发送时修改。 但是,如果后续需要更新PendingIntent,则应该使用FLAG_UPDATE_CURRENT和FLAG_MUTABLE。 最后,请记住,TaskOrganizer和RootTask相关的API在Android 10及以上版本引入,且为隐藏API,需要使用反射或直接调用(如果拥有系统权限)。 如果您的应用不是系统应用,则无法使用此方法。您可以考虑使用Android官方提供的分屏API(如ActivityOptions.setLaunchDisplayId)来实现在不同屏幕显示,但无法精确控制分屏位置。 替代方案:使用系统分屏模式 如果不需要同时启动两个Activity,可以让用户手动分屏: 1. 启动第一个Activity。 2. 然后启动第二个Activity,并调用startActivityWithIntent,同时使用Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT(要求API 24+),这样第二个Activity会启动到分屏的另一个区域。 但是,这需要用户手动进入分屏模式。 代码示例(普通应用): ```java // 启动第一个Activity Intent intent1 = new Intent(context, TargetActivity.class); intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent1); // 启动第二个Activity到分屏区域 Intent intent2 = new Intent(context, TargetActivity.class); intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); context.startActivity(intent2); ``` 这种方法不需要系统权限,但需要用户设备支持分屏,并且用户已经开启了分屏模式(或者由第一个Activity触发分屏模式)。 因此,根据您的应用权限和需求选择方案。 由于您的问题中提到了TaskOrganizer,我们假设您正在开发系统应用,所以提供了系统级的实现方案。 请根据实际情况调整。</think>在 Android 中通过 `PendingIntent` 和 `TaskOrganizer` 将同一个 Activity 启动到两个分屏区域需要系统级权限,主要涉及以下关键步骤: ### 解决方案步骤 1. **创建分屏容器**(需要系统权限) ```java // 创建 TaskOrganizer 实例 TaskOrganizer taskOrganizer = new TaskOrganizer(); // 创建两个分屏容器(左/右) TaskContainer leftContainer = taskOrganizer.createTaskContainer( new TaskContainerConfiguration.Builder() .setPosition(0, 0) .setSize(screenWidth/2, screenHeight) // 左半屏 .build() ); TaskContainer rightContainer = taskOrganizer.createTaskContainer( new TaskContainerConfiguration.Builder() .setPosition(screenWidth/2, 0) .setSize(screenWidth/2, screenHeight) // 右半屏 .build() ); ``` 2. **构建带任务 ID 的 PendingIntent** ```java // 创建基础 Intent Intent leftIntent = new Intent(context, TargetActivity.class); leftIntent.putExtra("REGION", "left"); // 设置启动到指定容器 ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchTaskId(leftContainer.getTaskId()); // 关键:绑定到左容器 // 创建 PendingIntent (Android 12+ 需 FLAG_IMMUTABLE) PendingIntent leftPendingIntent = PendingIntent.getActivity( context, REQUEST_CODE_LEFT, leftIntent, PendingIntent.FLAG_IMMUTABLE, options.toBundle() // 传入任务容器ID ); // 同理创建右分屏的 PendingIntent Intent rightIntent = ... // 设置不同 REQUEST_CODE options.setLaunchTaskId(rightContainer.getTaskId()); PendingIntent rightPendingIntent = ... ``` 3. **触发分屏启动** ```java try { leftPendingIntent.send(); rightPendingIntent.send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); } ``` ### 关键技术点说明 1. **TaskOrganizer 系统权限要求**: - 此 API (`android.window.TaskOrganizer`) 属于系统级接口 - 需要 `MANAGE_ACTIVITY_TASKS` 权限(仅系统签名应用可用) - 普通应用无法直接使用,需通过系统应用代理[^1][^4] 2. **分屏容器绑定原理**: - 每个 `TaskContainer` 生成独立任务 ID (`taskId`) - 通过 `ActivityOptions.setLaunchTaskId()` 绑定启动位置 - 同一 Activity 在不同容器中视为不同实例[^3] 3. **PendingIntent 注意事项**: - Android 12+ 必须指定 `FLAG_IMMUTABLE` - 不同分屏需使用不同 `REQUEST_CODE` - 通过 `Intent` extras 区分实例逻辑(如 "left"/"right")[^1] ### 备选方案(普通应用) 若无系统权限,可通过官方分屏 API 实现: ```java // 启动主Activity Intent mainIntent = new Intent(context, MainActivity.class); startActivity(mainIntent); // 启动分屏Activity Intent splitIntent = new Intent(context, TargetActivity.class); splitIntent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); ActivityOptions options = ActivityOptions.makeSplitScreenOptions(); startActivity(splitIntent, options.toBundle()); ``` > ⚠️ 此方式需用户手动进入分屏模式,无法精确控制窗口位置[^4] ### 总结 1. **系统级方案**:通过 `TaskOrganizer` + `setLaunchTaskId()` 精确控制分屏位置(需系统权限) 2. **标准方案**:使用 `FLAG_ACTIVITY_LAUNCH_ADJACENT` 触发系统分屏 3. **兼容性注意**:Android 12+ 必须使用 `FLAG_IMMUTABLE` 且分屏 API 要求 Android 7.0+[^1][^4]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值