听说点赞关注的人,身体健康,万事如意,工作顺利,爱情甜蜜,一夜暴富,升职加薪……最终迎娶白富美!!!
‼️微信公众号:炜煜工作室
🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱
📡 :安卓开发-基础知识补习12💯
📰内容简介:
本文介绍了安卓开发中的IPC,Activity的四种启动模式。,使用java代码进行开发,如果有问题的地方请不吝指教,如果对文内内容有不理解的地方,也希望能积极主动的联系博主进行深刻的探讨,以便于让博主更深刻的记住这篇博文的内容,好让博主在发光发热的道路上越走越远。[手动狗头]🐶努力,奋斗!
📎 标签:安卓;java;IPC;Activity启动模式;
🔍一、安卓中的IPC
- IPC:Inter-Process Communication,含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。
- 线程:是CPU调度的最小单元。一般指一个执行单元,PC和移动设备上指一个程序或者一个应用。
- 进程:一种有限的系统资源。一个进程可以包含多个线程。最简单的情况下,一个进程中可以只有一个线程,即主线程,在安卓里面主线程也叫UI线程,在UI线程里面才能操作界面元素。
- 很多时候,一个进程中需要执行大量的耗时任务,如果这些任务放在主线程中执行就会造成界面无法响应。严重影响用户体验,这种情况在PC系统和移动系统中都存在,在安卓中有一个叫做ANR(Application Not Respinding),即应用无响应。解决这个问题就需要用到线程。把一些耗时的任务放到线程中即可。
- IPC不是安卓独有的,任何一个操作系统都需要有响应IPC的机制。Windows上可以通过剪切板,管道,油槽等方式来进行进程间的通信;Linux上可以通过命名管道,共享内存,信号量等来尽心该进程之间的通信。可以看到不同的窜哦做系统平台有着不同的进程间的通信方式。
- 安卓中最有特色的进程间的通信方式是Binder,通过Binder可以i轻松地实现进程间通信。除了Binder,安卓还支持Socket,通过Socket也可以实现任意两个终端之间的通信,当然一个设备上两个进程通过Socket通信自然也是可以的。
为何需要IPC,多进程通信可能会出现的问题:
-
进程间内存数据不共享,不同的虚拟机和Application的
-
静态成员和单例模式完全失效。
-
线程同步机制完全失效。
-
SharedPreferences的可靠性下降。因为SharedPreferences不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失,这是应为SharedPreferences底层是通过读/写XML文件来实现的,并发写显然是可能出问题的,甚至并发读写都有可能出问题。
-
Application会多次创建,运行在不同的进程中的组件是属于两个不同的虚拟机和Application的。
-
安卓中IPC方式,各种方式优缺点:
名称 优点 缺点 适用场景 Bundle 简单易用 只能传输Bundle支持的数据类型 四大组件的进程间通信 文件共享 简单易用 不适合高并发场景,并且无法做到进程间的即时通信 无并发访问情形,交换简单的数据实时性不高的场景 AIDL 功能强大,支持一对多并发通信,支持实时通信 使用稍微复杂,需处理好线程同步 一对多通信切有RPC需求 Messenger 功能强大,支持一对多并发通信,支持实时通信 不能很好的处理高并发情景,不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型 低并发的一对多即时通信,无RPC需求,或者无需返回结果的RPC需求 ContentProvider 在数据源访问方面功能强大,支持一对多并发数据共享,可以通过Call方法扩展其他操作 可以理解为受约束的AIDL,主要提供数据源的CRUD操作 一对多的进程间数据共享 Socket 功能强大,可以通过网络传输字节流,支持一对多并发实时通信 实现细节稍微优点繁琐,不支持直接的RPC 网络数据交换
-
-
为什么选择Binder?
-
安卓也是Linux内核,Linux现有的进程通信手段有以下的几种:
- 管道:在创建时分配一个page大小的内存,缓存区大小比较有限。
- 消息队列:信息复制两次,额外的CPU消耗,不合适频繁或信息量大的通信。
- 共享内存:无需复制,共享缓存区直接附加到进程虚拟地址空间,速度快,但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决。
- 套接字:作为更通用的接口,传输效率低,主要用于不同机器或跨网络的通信。
- 信号量:常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等;
-
既然有现有的IPC方式,为什么重新设计一套Binder机制呢。主要是出于以上三个方面的考量:
**效率:传输效率主要影响因素是内存拷贝的次数,拷贝次数越少,传输速率越高。从Android进程架构角度分析:**对于消息队列、Socket和管道来说,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方的缓存区,一共两次拷贝。
而对于Binder来说,数据从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到同一块物理地址的,节省了一次数据拷贝的过程。
共享内存不需要拷贝,Binder的性能仅次于共享内存。
**稳定性:**上面说到共享内存的性能优于Binder,那为什么不采用共享内存呢,因为共享内存需要处理并发同步问题,容易出现死锁和资源竞争,稳定性较差。Socket虽然是基于C/S架构的,但是它主要是用于网络间的通信且传输效率较低。Binder基于C/S架构 ,Server端与Client端相对独立,稳定性较好。
**安全性:**传统Linux IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份;而Binder机制为每个进程分配了UID/PID,且在Binder通信时会根据UID/PID进行有效性检测。
-
🔍二、Activity启动模式
-
Activity作为四大组件之一中最重要的一个组件,负责App的视图,用户交互,经常和其他组件绑定使用,可以说非常重要。下面介绍一下Activity的四种启动模式
-
一个应用通常会有多个Activity,这些Activity都有一个对应的action如(MainActivity的action),我们可以通过action来启动对应的Activity(隐式启动)。
-
<acion android:name="android.intent.action.Main" />
-
一个应用程序可以说由一系列组件组成,这些组件以进程为载体,相互写作实现App的功能。
-
任务栈(Task Stack)或者叫做退回栈(Back Stack)
4.1.任务栈用来存放用户开启的Activity。
4.2.在应用程序创建之初,系统会默认分配给其一个任务栈(默认一个),并存储根Activity。
4.3.同一个Task Stack,只要不在栈顶,就是onStop状态:
4.4.任务栈的id自增长型,是Integer类型。
4.5.新创建Activity会被压入栈顶。点击back会将栈顶Activity弹出,并产生新的栈顶元素作为显示界面(onResume状态)。
4.6.当Task最后一个Activity被销毁时,对应的应用程序被关闭,清除Task栈,但是还会保留应用程序进程(狂点Back退出到Home界面后点击Menu会发现还有这个App的框框。个人理解应该是这个意思),再次点击进入应用会创建新的Task栈。
-
Activity的affinity:
5.1.affinity是Activity内的一个属性(在ManiFest中对应属性为taskAffinity)。默认情况下,拥有相同affinity的Activity属于同一个Task中。
5.2.Task也有affinity属性,它的affinity属性由根Activity(创建Task时第一个被压入栈的Activity)决定。
5.3.在默认情况下(我们什么都不设置),所有的Activity的affinity都从Application继承。也就是说Application同样有taskAffinity属性。
<application
android:taskAffinity=“gf.zy”
5.4.Application默认的affinity属性为Manifest的包名。
-
-
Activity的启动模式:
默认启动模式:Standard:当启动一个Activity时,如果这个Activity的启动模式为默认的standard模式,那么无论当前栈顶元素是否是它本身,他都会简单地新建一个Activity,并将其加到栈顶。
栈顶复用模式:SingleTop:如果栈顶Activity为我们要新建的Activity(目标Activity),那么就不会重复创建新的Activity。假如新建的Activity和栈顶的Activity是同一个Activity,那么就不会再新建。
<!--此处修改模式即可!--> <activity android:name=".FirstActivity" android:launchMode="singleTop"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
和Standard模式同样的代码,只是修改了启动模式,点击按钮之后不会再创建多余的自己了,这样及时系统卡顿,网络延迟,也可以消除堆叠多个同样Activity的情况。
SingleTask:栈内复用模式:与SingTop模式类似,只不过singleTop模式只是针对栈顶的元素,而singleTask模式下,如果task栈内存在目标Activity实例则:- 将task内的对应的Activity实例之上的所有Activity弹出栈。
- 将对应的Activity置于栈顶,获得焦点。
当启动一个launchMode为singleTask的Activity时,假设之前没有创建过就需要重新创建;有,就直接使用原来的那个,并且将其上所有Activity全部出栈。
singleInstance:全局唯一模式:在该模式下,我们会为目标Acitvity分配一个新的affinity,并创建一个新的Task栈,将目标Activity放入新的Task,并让目标Activity获得焦点。新的Task有且只有这一个Activity实例。如果已经创建过目标Activity实例,则不会创建新的Task,而是将以前创建的Activity唤醒(对应Task设为Foreground状态)。名称是单例模式,也即,系统中只有那么一个实例。既然只有一个,那么也就说明很重要、很特殊咯,我们需要将其“保护起来”。安卓对单例模式的“保护措施”是将其单独放到一个任务栈中。假设现在有A、B、C、D四个Activity,其中B为singleInstance模式,而其他是standard模式。A启动B,B启动C,C启动D,那么此时栈中的情况如何呢?我们说了,B需要单独放入一个栈中,所以这个时候会存在两个栈,一个中的内容为A->C->D,一个为B。现在我们已经在D活动了,依次按返回键销毁这些活动,那么C是否会返回B呢?答案是否定的,因为B和C不在一个栈中,一次会C无法返回B,而是直接返回A。从A返回会并不会直接退出程序,而是出现B。因为此时存在两个任务栈,第一个栈中的A、C、D均已经被销毁,系统就找到了另一个栈中的B,将B也销毁,才会完全退出程序。
🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱文章来源:https://www.toymoban.com/news/detail-400542.html
📌内容总结:
🕥本文介绍了.安卓开发中的IPC,Activity的四种启动模式,还有🐛没有写到本文内,后续内容可以继续追踪博主的后续文章,或许会介绍相关的内容,如果没介绍,请用力踢一脚,好让摸鱼的博主积极主动的去认识错误并及时改正,在发光发热的道路上越走越远……
表情网站:🎁 Emoji cheat sheet for GitHub, Basecamp, Slack & more (webfx.com)文章来源地址https://www.toymoban.com/news/detail-400542.html
到了这里,关于安卓开发-基础知识补习12的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!