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.mzph.cn/news/106519.shtml

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

相关文章

【Express】服务端渲染(模板引擎 EJS)

EJS(Embedded JavaScript)是一款流行的模板引擎,可以用于在Express中创建动态的HTML页面。它允许在HTML模板中嵌入JavaScript代码,并且能够生成基于数据的动态内容。 下面是一个详细的讲解和示例,演示如何在Express中…

Mac安装Kali保姆级教程

Mac安装Kali保姆级教程 其他安装教程:使用VMware安装系统Window、Linux(kali)、Mac操作系统 1 虚拟机安装VM Fusion 去官网下载VM Fusion 地址:https://customerconnect.vmware.com/en/evalcenter?pfusion-player-personal-13 …

网工记背配置命令(3)----POE配置示例

POE 供电就是通过以太网供电,这种方式仅凭借那根连接通信终端的网线就可完成为它们供电。POE提供的是-53V~0v 的直流电,供电距离最长可达 100m。PoE 款型的交换机的软件大包天然支持 POE,无需 license,通过执行 poe-enable 命令使…

Android 10.0 禁止弹出系统simlock的锁卡弹窗功能实现

1.前言 在10.0的系统开发中,在一款产品中,需要实现simlock锁卡功能,在系统实现锁卡功能以后,在开机的过程中,或者是在插入sim卡 后,当系统检测到是禁用的sim卡后,就会弹出simlock锁卡弹窗,要求输入puk 解锁密码,功能需求禁用这个弹窗,所以就需要看是 哪里弹的,禁用…

记一次生产大对象及GC时长优化经验

最近在做一次系统整体优化,发现系统存在GC时长过长及JVM内存溢出的问题,记录一下优化的过程 面试的时候我们都被问过如何处理生产问题,尤其是线上oom或者GC调优的问题更是必问,所以到底应该如何发现解决这些问题呢,用真实的场景实操&#xff…

计算机毕业设计 基于协同过滤算法的白酒销售系统的设计与实现 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…

Apache Log4j Server (CVE-2017-5645) 反序列化命令执行漏洞

文章目录 Apache Log4j Server 反序列化命令执行漏洞(CVE-2017-5645)1.1 漏洞描述1.2 漏洞复现1.2.1 环境启动1.2.2 漏洞验证1.2.3 漏洞利用 1.3 加固建议 Apache Log4j Server 反序列化命令执行漏洞(CVE-2017-5645) 1.1 漏洞描述…

【大数据】Hive SQL语言(学习笔记)

一、DDL数据定义语言 1、建库 1)数据库结构 默认的数据库叫做default,存储于HDFS的:/user/hive/warehouse 用户自己创建的数据库存储位置:/user/hive/warehouse/database_name.db 2)创建数据库 create (database|…

allegro中shape的一些基本操作(一)——添加和修改shape

添加shape 简单添加shape的方式有3种,如下图所示 点击选择相应的shape模式后可以在option面板中设置相应的shape参数(这里不做过多介绍,里面可以设置shape的大小、静态或动态shape等参数),然后再用鼠标在相应的层上添…

计算机网络 | 网络层

计算机网络 | 网络层 计算机网络 | 网络层功能概述SDN(Software-Defined Networking)路由算法IPv4IPv4 分组IPv4 分组的格式IPv4 数据报分片 IPv4 地址与 NATIPv4 地址网络地址转换(NAT) 子网划分和子网掩码子网划分子网掩码 无分…

Hadoop3教程(十二):MapReduce中Shuffle机制的概述

文章目录 (95) Shuffle机制什么是shuffle?Map阶段Reduce阶段 参考文献 (95) Shuffle机制 面试的重点 什么是shuffle? Map方法之后,Reduce方法之前的这段数据处理过程,就叫做shuff…

【opencv】windows10下opencv4.8.0-cuda Python版本源码编译教程

【opencv】windows10下opencv4.8.0-cuda Python版本源码编译教程 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【opencv】windows10下opencv4.8.0-cuda Python版本源码编译教程前言准备工具anaconda/cuda/cudnnanaconda创建环境(选做)安装原…

Opencv——颜色模型+通道分离与合并

视频加载/摄像头调用 VideoCapture允许一开始定义一个空的对象 VideoCapture video VideoCapture(const String &filename,int apiPreferenceCAP_ANY) filename:读取的视频文件或者图像序列名称 apiPreference:读取数据时设置的属性,例如编码格式、是否调用Op…

LabVIEW为什么不能在RT机箱内看到NI-IMAQ设备

LabVIEW为什么不能在RT机箱内看到NI-IMAQ设备 最近把NI-IMAQ更新到最新的1394版本。这个新驱动工作良好。但是,当打开MAX,NII MAQ设备却在RT PXI机箱里找不到。 问题最有可能是NIIMAQ服务器的版本跟主机PC和RT目标设备是不同的。为保证通信正常NII MAQ服…

FFmpeg截图命令优化

由于项目要求,需要对摄像机的rtsp流进行截图。一开始我使用了命令: ./ffmpeg -ss 0 -i XXX -f image2 -vframes 1 -s 370*210 -y output.jpg 上述命令抓取rtsp流第0秒(当前)的图像,将其保存为370*210分辨率的jpg图片…

08Maven中的继承和聚合的作用

Maven中的继承 实际开发中对一个比较大型的项目进行了模块拆分 , 一个project下面创建了很多个modul, 每一个module都需要配置自己的依赖信息 开发中使用的同一个框架内的不同jar包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一 传统方…

机器人硬件在环仿真:解决实体开发与测试挑战,提升效率与安全性

工业机器人具备出色的灵活性和运动能力,广泛应用于工业制造领域。它们可以完成装配、焊接、喷涂、搬运、加工、品质检测等任务,提高了生产效率,保证了产品质量。此外,在医疗领域也有辅助手术等特殊应用,展现了其在多个…

Flash-Attention

这是一篇硬核的优化Transformer的工作。众所周知,Transformer模型的计算量和储存复杂度是 O ( N 2 ) O(N^2) O(N2) 。尽管先前有了大量的优化工作,比如LongFormer、Sparse Transformer、Reformer等等,一定程度上减轻了Transformer的资源消耗…

k8s-10 cni 网络

k8s通过CNI接口接入其他网络插件来实现网络通讯。目前比较流行的插件有flannel,calico等。 CNI插件存放位置: # cat /etc/cni/net.d/10-flannel.conflist 插件使用的解决方案如下: 虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。多路复用: Mac…

MAC上设置IDEA如何一个窗口打开多个项目,多个tab

1、IDEA一个窗口打开多个项目 如果你打开了多个项目、每次切换都要半天,想让项目都汇聚到top栏 点击 Window - Merge All Project Windows 即可 但是这样比较挫,每次打开新的项目都还是会重新打开一个IDEA窗口 so,如何设置项目在同一个窗口…