听说点赞关注的人,身体健康,万事如意,工作顺利,爱情甜蜜,一夜暴富,升职加薪……最终迎娶白富美!!!
‼️微信公众号:炜煜工作室
🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱
进程间内存数据不共享,不同的虚拟机和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现有的进程通信手段有以下的几种:
既然有现有的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作为四大组件之一中最重要的一个组件,负责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属性。
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实例则:
当启动一个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也销毁,才会完全退出程序。
🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱
表情网站:🎁 Emoji cheat sheet for GitHub, Basecamp, Slack & more (webfx.com)