Android---Android 是如何通过 Activity 进行交互的

相信对于 Android 工程师来说,startActivity 就像初恋一般。要求低,见效快,是每一个菜鸟 Android 工程师迈向高级 Android 工程师的必经阶段。经过这么多年的发展,startActivity 在 google 的调教下已经变得愈发成熟,对工程师的要求也越来越高。、

taskAffinity

通过设置不同的启动模式可以实现调配不同的 Task,但是 taskAffinity 在一定程度上也会影响任务栈的调配流程。每一个 Activity 都有一个 Affinity 属性,如果不在清单文件(AndroidManifest.xml)文件中指定,默认为当前应用的包名。taskAffinity 主要有以下几点需要注意:

1. taskAffinity 会默认使 Activity 在新的栈中分配吗?

在一个 Android 项目 LagouTaskAffinity 中,创建两个 Activity,First 和 Second。除了类名之外,其他都是默认配置。

点击 First 中的 Button,从 First 页面跳转到 Second 页面。然后命令行中执行以下命令

adb shell dumpsys activity activities

这个命令会将系统中所有存活的 Activity 信息打印到控制台,如下:

上图中的 TaskRecord 代表一个任务栈。在这个栈中存在两个 Activity 实例,First 和 Secode。其中,Second 位于栈顶。

接下来,修改 Second 的 taksAffinity 为 lagou.affinity,使他也 First 的不同。

重写运行代码,并再次查看任务栈中的代码,如下:

从上图可以看出,虽然 First 和 Second 的 taskAffinity 不同,但是它们都被创建在一个任务栈中。

如果将 Second 的 launchMode(启动模式) 改为 singleTask,再次重新运行,结果如下:

两个 Activity 被分配到了不同的任务栈中。

所以回到上面的问题,taskAffinity 会默认使 Activity 在新的栈中分配吗?

答案是:不会。单纯使用 taskAffinity 不能导致 Activity 被创建在新的任务中,需要配合 singleTask 或者 singleInstance

2. taskAffinity + allowTaskReparenting

allowTaskReparenting 赋予 Activity 在各个 Task 中间转移的特性。一个在后台任务栈中的 Activity A,当有其他任务进入前台,并且 taskAffinity 与 A 相同,则会自动将 A 添加到当前启动的任务栈中。

生活中的场景:

1. 在某外卖App 中下好订单后,跳转到支付宝进行支付。当在支付宝中支付成功后,页面停留在支付宝支付成功页面。

2. 按 Home 键(支付成功的页面加入到了后台任务栈中),在主页面重新打开支付宝,页面上显示的是之前的支付成功页面。(有一个与"支付成功"页面相同taskAffinity的任务进入到前台)

3. 再次进入外面 App,可以发现支付成功页面已经消失。

造成上面现象的原因就是 allowTaskReparenting 属性。

实例演示

分别创建2个Android工程: First 和 TaskAffinityReparent

●在First中有3个Activity: FirstA、 FirstB、 FirstC,打开顺序依次是FirstA -> FirstB -> FirstC 。其中FirstC的taskAffinity为“lagou.affinity” ,且allowTaskReparenting属性设置为true

● TaskAffinityReparent 中只有一个 Activity:ReparentActivity,并且其TaskAffinity也等于“lagou.affinity”。

● 将这两个项目分别安装到手机上之后,打开First App。并从FirstA开始跳转到FirstB,再进入FirstC页面,然后按Home键,使其进入后台任务。

此时,系统中的 Activity 信息如下

● 打开TaskAffinityReparent 项目。屏幕上本应该显示 ReparentActivity,但实际上显示的却是 FirstC的内容。并且系统中 Activity 信息如下:

可以看出 FirstC 已经从后台任务栈中移动到与 ReparentActivity 相同的任务栈中。并且,FirstC 位于栈顶位置,再次点击返回键,才会显示 ReparentActivity 的内容。

通过 Binder 传递数据的限制

Activity 在界面跳转时,使用 Intent 传递数据是最常用的操作。但 Intent 传值偶尔也会导致程序崩溃。如下代码所示:

public void startFirstB(View view){Intent intent = new Intent(this, FirstB.class);intent.putExtra("bean", new Bean()); // 传递 Bean 中的数据startActivity(intent);
}static class Bean implements Serializable{private byte[] data = new byte[1024 * 1024];String str = "data string";
}

在 startFirstB 中跳转 FirstB 页面,并通过 Intent 传递 Bean 中数据。但是,执行上述代码会报如下错误

上面日志中的信息是,intent 中的数据过大。最终的原因是 Android 对使用 Binder 传递数据进行了限制,通常情况为 1MB。但是,根据不同版本、不同厂商,这个值会有区别。

解决 Binder 传递数据的限制

1. 减少通过 Intent 传递的数据,将非必须字段使用 transient 关键字修饰。

比如上述代码 Bean 类中,byte 类型数据 data 并非必须使用的数据,则需要避免将其序列化,如下所示:

添加 transient 修饰后,再次运行代码,则不会再报异常。

2. 将对象转化为 Json 字符串,减少数据体积。

将类中数据转化为 JSON 字符串可以减少数据大小,比如使用 Gson.toJson() 方法。大多数时候,将类转化为 Json 字符串之后,还是会超出 Binder 限制,说明实际要传递的数据是很大的。这种情况则需要考虑使用本地持久化来实现数据共享,或者使用 EventBus 来实现数据传递

通过 Process 造成多个 Application

在自定义的 Application 中做一些初始化的操作,比如 App 分包、推送初始化、图片加载库的全局配置等。 

但实际上,Activity 可以在不同的进程中启动。而每一个进程都会创建一个 Application,因此有可能造成 Appcation 的 onCreate() 方法被多次执行,比如以下代码:

RemoteActivity 的 process 为 “lagou.process”,这会导致它在一个新的线程中创建。当中 MainActivity 跳转到 RemoteActivity 时,LagouApplication 会被再次创建。其代码如下:

最终打印日志如下:

可以看出,LagouApplication 的 onCreate() 方法被创建了2次。因此,各自初始化的操作也会执行2次。

解决办法:2种比较好的处理方法:

\bullet onCreate 方法中判断进程的名称,只有在符合要求的进程里,才执行初始化操作;

\bullet 抽象出一个与 Application 生命周期同步的类,并根据不同的进程创建相应的 Application 实例。

后台启动 Activity 失效

试想这样一种情况,当用户正在玩着游戏,手机后台可能有某个下载 apk 的任务,但 apk 下载完之后,突然弹出 apk 安装界面,中断了游戏界面的交互。这种情况便造成了极差的用户体验。

为了避免这种情况的发生,从 Android10(API 29) 开始,Android 系统对后台进程启动 Activity 做了一定限制。主要目的就是避免当前的交互不被打断。

但是,这也造成了一些其它实际问题,例如

在项目中有 Force Update 功能,当用户选择升级之后会在后台进行新的安装包下载任务。正常情况下下载功能要弹出 apk 安装界面,但是在某一版升级时突然很多用户反馈无法弹出下载界面。经过查看抓取的 log 信息,最终发现有个特点就是都发生在 Android 10 版本,是版本兼容问题。

Android 官方建议使用通知来替代直接启动 Activity 操作。也就是,当后台执行的任务执行完毕,并不会直接调用 startActivity 来启动新的界面。而是通过 notificationManager 来发送 notification 到状态栏。这样,既不会影响当前的交互操作,用户也能及时获取后台的进展情况。

 总结

使用startActivity时可能会遇到的问题:

● taskAffinity 实现任务栈的调配;

● 通过Binder传递数据的限制;

● 多进程应用可能会造成的问题;

● 后台启动Activity的限制。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/160074.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅析ArkTS的起源和演进

1 引言 Mozilla创造了JS,Microsoft创建了TS,Huawei进一步推出了ArkTS。 从最初的基础的逻辑交互能力,到具备类型系统的高效工程开发能力,再到融合声明式UI、多维状态管理等丰富的应用开发能力,共同组成了相关的演进脉…

JimuReport 积木报表 v1.6.4 稳定版本正式发布 — 开源免费的低代码报表

项目介绍 一款免费的数据可视化报表,含报表和大屏设计,像搭建积木一样在线设计报表!功能涵盖,数据报表、打印设计、图表报表、大屏设计等! Web 版报表设计器,类似于excel操作风格,通过拖拽完成报…

内容分发网络CDN分布式部署真的可以加速吗?原理是什么?

Cdn快不快?她为什么会快?同样的带宽为什么她会快?原理究竟是什么,同学们本着普及知识的想法,我了解的不是很深入,适合小白来看我的帖子,如果您是大佬还请您指正错误的地方,先谢谢大佬…

[部署网站]01安装宝塔面板搭建WordPress

宝塔面板安装WordPress(超详细)_Wordpress主题网 参考教程 宝塔面板 - 简单好用的Linux/Windows服务器运维管理面板 官网 1.首先你需要一个服务器或者主机 (Windows系统或者Linux系统都可以) 推荐Linux系统更稳定,…

设计模式:简单工厂模式(C#、JAVA、JavaScript、C++、Python、Go、PHP):

简介: 简单工厂模式,它提供了一个用于创建对象的接口,但具体创建的对象类型可以在运行时决定。这种模式通常用于创建具有共同接口的对象,并且可以根据客户端代码中的参数或配置来选择要创建的具体对象类型。 在简单工厂模式中&am…

SaaS系统用户权限设计

SaaS系统用户权限设计 学习目标: 理解RBAC模型的基本概念及设计思路 了解SAAS-HRM中权限控制的需求及表结构分析完成组织机构的基本CRUD操作 完成用户管理的基本CRUD操作完成角色管理的基本CRUD操作 组织机构管理 需求分析 需求分析 实现企业组织结构管理&#xff0…

期中考Web复现

第一题 1z_php <?php //Yeedo told you to study hard! echo !(!(!(!(include "flag.php")||(!error_reporting(0))||!isset($_GET[OoO])||!isset($_GET[0o0])||($_GET[OoO]2023)||!(intval($_GET[OoO][0])2023)||$_GET[0o0]$_GET[OoO]||!(md5($_GET[0o0])md5($_…

VM虚拟机运行的Ubuntu连入同一局域网,并实现双机方法

环境&#xff1a; Windows 10 VMware Workstation Pro 16 Ubuntu 20.4 在虚拟机设置桥接模式 确保虚拟机处于关闭状态&#xff0c;在Vm中设置&#xff1a; 编辑->虚拟网络编辑器 如果你以前设置过&#xff0c;可以重置之。 重置之后&#xff0c;添加桥接模式&#xff1a; …

启动速度提升 10 倍:Apache Dubbo 静态化方案深入解析

作者&#xff1a;华钟明 文章摘要&#xff1a; 本文整理自有赞中间件技术专家、Apache Dubbo PMC 华钟明的分享。本篇内容主要分为五个部分&#xff1a; -GraalVM 直面 Java 应用在云时代的挑战 -Dubbo 享受 AOT 带来的技术红利 -Dubbo Native Image 的实践和示例 -Dubbo…

用批处理连续ping一个ip段

今天写这个有一个原因&#xff0c;就是我家的网络用了一个无线电力猫做为无线网络扩展&#xff0c;但忘记了无线电力猫的IP&#xff0c;而且我家新路由器也看不到这个电力猫&#xff0c;也可能有一个原因。我原来用的是192.168.1.1的华为路由器&#xff0c;自然我就把这个无线电…

2022最新版-李宏毅机器学习深度学习课程-P17 卷积神经网络CNN

一、CNN 用于图像分类 需要图片大小统一 彩色图像分为R G B 三层&#xff0c;展平后首尾相接 值代表着颜色的强度 图像识别中不需要全连接的&#xff0c;参数太多了 观测1&#xff1a;通过判断多个小局部图像就能判断出图片标签 感受野的定义 简化1 感受野可以重叠&#xff…

接口自动化测试框架搭建【附教程加源码】

1 接口测试 接口测试是对系统或组件之间的接口进行测试&#xff0c;主要是校验数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及相互逻辑依赖关系。 接口自动化相对于UI自动化来说&#xff0c;属于更底层的测试&#xff0c;这样带来的好处就是测试收益更大&#xff…

网络安全分析——蠕虫病毒动态分析视图

蠕虫病毒&#xff08;Worm Virus&#xff09;是一种自我复制的恶意软件&#xff0c;通过网络或系统漏洞传播&#xff0c;感染其他计算机并利用其资源。与其他病毒不同&#xff0c;蠕虫病毒无需依赖于宿主文件&#xff0c;并可以自动在网络中传播&#xff0c;因此具有高度传染性…

【面试经典150 | 区间】汇总区间

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;一次遍历复杂度分析 其他语言python3C 写在最后 Tag 【一次遍历】【数组】【字符串】 题目来源 228. 汇总区间 题目解读 给定一个无重复的升序数组 nums&#xff0c;需要将这个数组按照以下规则进行汇总&#xff1…

SGPT: GPT Sentence Embeddings for Semantic Search

简介 语义搜索分为两个部分&#xff1a; 1.搜索和query 相关的topk文档。 2.理解文档和query后面隐藏的语义信息&#xff0c;而不是字面含义。 这篇论文提出了SGPT模型&#xff0c;只用decoder-only的transformer来进行语义搜索和sentence向量的提取。 1.SGPT-BE&#xff1a;来…

13-k8s-ingress网络

文章目录 一、ingress介绍二、创建nginx和tomcat供测试三、创建ingress-http四、yaml方式安装ingress五、helm方式安装ingress&#xff08;推荐&#xff09;六、Ingress的HTTPS代理 一、ingress介绍 Service对集群之外暴露服务的主要方式有两种&#xff1a;NotePort和LoadBalan…

MySQL进阶(再论JDBC)——JDBC编程思想的分析 JDBC的规范架构 JDBC相关的类分析

前言 SQL&#xff08;Structured Query Language&#xff09;是一种用于管理关系型数据库的标准化语言&#xff0c;它用于定义、操作和管理数据库中的数据。SQL是一种通用的语言&#xff0c;可以用于多种关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;如MySQ…

电力物联网关智能通讯管理机-安科瑞黄安南

众所周知&#xff0c;网关应用于各种行业的终端设备的数据采集与数据分析&#xff0c;然后去实现设备的监测、控制、计算&#xff0c;为系统与设备之间建立通讯联系&#xff0c;达到双向的数据通讯。 网关可以实时监测并及时发现异常数据&#xff0c;同时自身根据用户规则进行…

nginx.4——正向代理和反向代理(七层代理和四层代理)

1、正向代理反向代理 nginx当中有两种代理方式 七层代理(http协议) 四层代理(tcp/udp流量转发) 七层代理 七层代理&#xff1a;代理的是http的请求和响应。 客户端请求代理服务器&#xff0c;由代理服务器转发给客户端http请求。转发到内部服务器&#xff08;可以单台&#…

Avalonia 实现跨平台的视频聊天、屏幕分享(源码,支持Win、银河麒麟、统信UOS)

现在最火的.NET跨平台UI框架莫过于Avalonia了。Avalonia 基于.NET Core&#xff0c;因此它可以运行在任何支持.NET Core的平台上。之前基于CPF跨平台UI框架写过一个视频聊天的demo&#xff0c;而现在看来Avalonia是大势所趋&#xff0c;于是&#xff0c;我再写一个Avalonia版本…