Android查缺补漏(IPC篇)-- 进程间通讯基础知识热身
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8479282.html
在Android中进程间通信是比较难的一部分,同时又非常重要,针对进程间通信,博主会用四篇文章来介绍,本篇文章为IPC系列的开篇,主要介绍一些IPC中用到的一些概念、基础等,目的是让读者朋友们在学习IPC之前对一些必要的知识有一个大体的把握。在Android中进程间通讯的方式有很多种,在后续的三篇中会分别介绍每一种方式的实现过程已经各自的优缺点。
进程间通讯篇系列文章目录:
- Android查缺补漏(IPC篇)-- 进程间通讯基础知识热身
- Android查缺补漏(IPC篇)-- Bundle、文件共享、ContentProvider、Messenger四种进程间通讯介绍
- Android查缺补漏(IPC篇)-- 进程间通讯之AIDL详解
- Android查缺补漏(IPC篇)-- 进程间通讯之Socket简介及示例
IPC是什么?
IPC(全称:Inter-Process Communication)为进程间通讯,指至少两个进程间传递数据或信号的一些技术活方法。
注:进程间通讯是至少两个进程之间发生的事情,我们通常习惯性的会把一方称为客户端,一方称为服务端,在后续的文章也会多次出现客户端和服务端,没接触过进程间通信的童鞋可能一开始会不太习惯,这里要注意一下。
为什么要使用IPC?
无论是在计算机系统还是Android系统中每个进程都有自己一部分独立的系统资源,彼此是隔离的,为了能是不同的进程互相访问资源并协同工作,就需要用到进程间通讯。
RPC是什么?
RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。(-来自百度百科)
在后面介绍AIDL时会用到RPC的概念,在这里简要说明一下RPC在Android的进程间通讯所扮演的角色,以博主本人的理解,简单来说RPC机制就是指在本地即可调用远程进程中的方法,而不需要关心其底层实现。
在Android中IPC有哪几种实现方式?
- Bundle
- 文件共享
- ContentProvider
- Messager
- AIDL
- Socket
如何开启一个进程
在四大组件的AndroidManifest配置中配置process属性
比如这个:
<service
android:name=".messager.MessengerService"
android:exported="true"
android:process=":remote" />
“:”开头和不带“:”的有什么区别:
“:”开头的进程属于当前应用的私有进程,其他应用的组件不能和它跑在同一进程下。
不带“:”的进程属于全局进程,其他应用可以通过ShareUID和它跑在同一进程下。
Android系统会为每一个应用分配一个UID,具有相同的UID才能共享数据。
通过ShareUID跑在同一进程中需要两个应用有相同的ShareUID并且有相同的签名才可以。
Android系统为每一个进程分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致不同的虚拟机访问同一个类的对象会产生多个副本。
使用多进程会导致如下问题:
- 静态变量和单例失效
- 线程同步机制失效
- SharePreference可靠性下降
- Application多次创建
IPC中涉及到的基础概念
- Serializable
- Parcelable
- Binder
Serializable
使用Serializable进行序列化很简单,只需要实现Serializable接口,然后为类指定一个serialVersionUID即可。
Serializable中的serialVersionUID工作机制:
- 序列化时系统会把当前类的serialVersionUID写入序列化的文件中(或其他中介)
- 反序列化时系统去检测文件中的serialVersionUID,对比是否和当前类的seralVersionUID一致。
- 一致就说明序列化的类的版本和当前类的版本是相同的,可以成功反序列化,否则就说明当前类和序列化的类相比发生了某些转换,就会报错(java.io.InvalidClassException)
- 静态变量属于类不属于对象,不参与序列化过程
- 用transient关键字标记的成员变量不参与序列化过程
Parcelable
使用Parcelable进行序列化比Serializable要麻烦一些,需要实现Parcelable接口,并实现一些必要方法,其通常形式如下:
public class Contact implements Parcelable {
public int phoneNumber;
public String name;
public String address;
public Contact(int phoneNumber, String name, String address) {
this.phoneNumber = phoneNumber;
this.name = name;
this.address = address;
}
public Contact() {
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(phoneNumber);
dest.writeString(name);
dest.writeString(address);
}
public void readFromParcel(Parcel parcel) {
phoneNumber = parcel.readInt();
name = parcel.readString();
address = parcel.readString();
}
public final static Creator<Contact> CREATOR = new Creator<Contact>() {
@Override
public Contact createFromParcel(Parcel source) {
return new Contact(source);
}
@Override
public Contact[] newArray(int size) {
return new Contact[size];
}
};
public Contact(Parcel parcel) {
phoneNumber = parcel.readInt();
name = parcel.readString();
address = parcel.readString();
}
}
一个类只要实现了Parcelable接口,其对象就可以实现序列化并可以通过Intent和Binder传递。
- Parcelable中的Parcel内部包含了可序列化的数据,可以在Binder中自由传输。
- 序列化功能:writeToParcel实现,最终是通过Parcel中的一系列write方法完成。
- 反序列化:CREATOR完成,通过Parcel的一系列read方法来完成,内部表明了如何创建序列化对象和数组。
- 内容描述:describeContents:仅当当前对象中存在文件描述符时返回1,其余所有情况返回0。
- 反序列化过程需要传递当前线程的上下文类加载器,否则会报找不到类的错误。
Serializable和Parcelable的区别:
- Serializable是java中的序列化接口,使用简单,但开销很大,序列化和反序列化过程需要大量IO操作。
- Parcelable是Android中的接口,使用麻烦,但效率高,首选。
- Parcelable主要适用于内存序列化上,但通过Parcelable将对象序列化到设备中或序列化后通过网络传输也可以,但稍微复杂,建议这种情况用Serializable。
Binder的使用及上层原理
- Binder是Android中的一个类,实现了IBinder接口
- 从IPC角度来说,Binder是一种跨进程通讯方式
- 从android framework角度来说,Binder是ServiceManager链接各种Manager(ActvitiyManager、WindowManager等等)和相应ManagerService的桥梁;
- 从android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService时,服务端会返回一个包含了服务端业务调用的Binder对象
AIDL中自动生成的Binder接口类的一些方法:
- DESCRIPTOR:Binder的唯一标识,一般用类名
- asInterface(IBinder obj):用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象。(如果客户端和服务端位于同一进程,此方法返回的就是服务端的Stub对象本身,否则返回Stub.proxy)
- asBinder:返回当前的Binder对象
- onTransact:运行在服务端的Binder线程池中
Binder运行在服务端进程,如果服务端进程被异常终止,Binder链接就会断裂,导致我们远程调用失败。但是此时我们并不知道Binder链接已经中断,为了解决这个问题,Binder中提供了两个配对的方法:
- linkToDeath:通过它可以给Binder设置一个死亡代理,当Binder死亡后我们就会收到通知。
如何设置Binder死亡代理:
首先声明一个DeathRecipeint对象,然后通过binder.linkToDeath()方法将其绑定到binder上。在DeathRecipeint内部有一个方法binderDied,当Binder死亡后,系统就会回调binderDied方法。
示例代码如下:
private ServiceConnection serviceConnection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIContactsManager = IContactsManager.Stub.asInterface(service);
Log.i(TAG, "onServiceConnected: mIContactsManager=" + mIContactsManager);
try {
// 给service设置死亡代理
service.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
...
};
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
// 当binder挂掉后就会执行此方法
if (mIContactsManager == null) {
return;
}
// 首先移除之前绑定的死亡代理
mIContactsManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
mIContactsManager = null;
// 然后重新绑定远程服务
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
};
进程间通讯的基础知识就先介绍到这里,接下来将开始针对每种进程间通讯方式作出详细的介绍。
最后想说的是,本系列文章为博主对Android知识进行再次梳理,查缺补漏的学习过程,一方面是对自己遗忘的东西加以复习重新掌握,另一方面相信在重新学习的过程中定会有巨大的新收获,如果你也有跟我同样的想法,不妨关注我一起学习,互相探讨,共同进步!
参考文献:
- 《Android开发艺术探索》
源码地址:本系列文章所对应的全部源码已同步至github,感兴趣的同学可以下载查看,结合代码看文章会更好。源码传送门
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8479282.html
Android查缺补漏(IPC篇)-- 进程间通讯基础知识热身的更多相关文章
- 知识点查缺补漏贴01-进程间通讯之mmap文件共享
引文: 个人名言:“同一条河里淹死两次的人,是傻子,淹死三次及三次以上的人是超人”.经历过上次悲催的面试,决定沉下心来,好好的补充一下基础知识点.本文是这一系列第一篇:进程间通讯之mmap. 一.概念 ...
- Android查缺补漏(IPC篇)-- Bundle、文件共享、ContentProvider、Messenger四种进程间通讯介绍
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8387752.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 进程间通讯之Socket简介及示例
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8425736.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 进程间通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(IPC篇)-- 款进程通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- Android查缺补漏(线程篇)-- IntentService的源码浅析
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8975114.html 在Android中有两个比较容易弄混的概念,Servic ...
- Android查缺补漏(View篇)--自定义 View 的基本流程
View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以 ...
- Android查缺补漏(View篇)--事件分发机制源码分析
在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 <Android查缺补漏(View篇)-- ...
- Android查缺补漏(View篇)--自定义View利器Canvas和Paint详解
上篇文章介绍了自定义View的创建流程,从宏观上给出了一个自定义View的创建步骤,本篇是上一篇文章的延续,介绍了自定义View中两个必不可少的工具Canvas和Paint,从细节上更进一步的讲解自定 ...
随机推荐
- respondsToSelector
SEL sel = @selector (start:) ; // 指定action if ([obj respondsToSelector:sel]) { //判断该对象是否有相应的方法 [obj ...
- 您是不是奇怪为什么 <script> 标签中没有 type="text/javascript" 属性?
在 HTML5 中该属性不是必需的.JavaScript 是 HTML5 以及所有现代浏览器中的默认脚本语言!
- Django将request对象传入模板配置
对于很多时候,需要从模板中获取很请求中很多内容,比如当前请求的url,当前的session变量中的某个值,这时候我们可以通过配置可将request对象传递进模板. django1.10版本: sett ...
- 利用神经网络算法的C#手写数字识别
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 下载Demo - 2.77 MB (原始地址):handwritten_character_recognition.zip 下载源码 - 70. ...
- 查看 Apache并发请求数及其TCP连接状态【转】
查看 Apache并发请求数及其TCP连接状态 (2011-06-27 15:08:36) 服务器上的一些统计数据: 1)统计80端口连接数netstat -nat|grep -i "80& ...
- 爬虫_网页url设计
为什么需要网页URL设计? 每个url不同的结构代表着不同的网页模块和信息的展现形式,为了方便维护与管理 网页url怎么设计? 分层: 主域名,子域名 一般形式为: 主域名: www.job.com ...
- js 数组与对象的区别
学习javascript的时候,我曾经一度搞不清楚”数组”(array)和”对象”(object)的根本区别在哪里,两者都可以用来表示数据的集合. 比如有一个数组a=[1,2,3,4],还有一个对 ...
- maven多模块搭建
此时你会发现父模块含有如下内容 这是因为创建的maven项目都带有样例,比如上图的这张图片 各种artifact都是做什么的呢,@参考文章中给出了答案 怎么创建不带这些呢? 那就创建simple pr ...
- SQLSERVER存储过程语法详解
CREATE PROC [ EDURE ] procedure_name [ ; number ] [ { @parameter data_type } [ VARYING ] [ = default ...
- PHP的CI框架流程基本熟悉
CI框架是PHP的一个快速开发框架,我是目前的公司项目后台语言用的PHP,因为我做前端开发,需要用php去填充页面数据,所以就开始去了解这个框架,学习了一些php和数据库的东西,这篇文章先具体介绍CI ...