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,从细节上更进一步的讲解自定 ...
 
随机推荐
- Java泛型解析
			
1. 概述 在引入范型之前,Java类型分为原始类型.复杂类型,其中复杂类型分为数组和类.引入范型后,一个复杂类型就可以在细分成更多的类型. 例如原先的类型List,现在在细分成List< ...
 - numpy 解一道简单数学题
			
题目 A group took a trip on a bus, at 3 per child and 3.20 per adult for a total of 118.40. They took ...
 - Python解析JSON详解
			
JSON 函数 使用 JSON 函数需要导入 json 库:import json. 函数 描述 json.dumps 将 Python 对象编码成 JSON 字符串 json.loads 将已 ...
 - python文件操作总结
			
python中对文件.文件夹(文件操作函数)的操作需要涉及到os模块和shutil模块. 得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目 ...
 - DOS、Mac 和 Unix 文件格式[转]
			
DOS.Mac 和 Unix 文件格式 相信很多朋友都碰到过这三种文件格式的互换问题,今日又碰到这个问题,忽然想寻根问底,于是整理了本文档. 文件格式区别 我们先看看这三个家伙有啥区别.很久以前, ...
 - win7下JAVA环境变量配置方法
			
1.首先,根据自己的需要下载1.6或者1.7的JDK,安装JDK.(安装的时候记一下安装目录,后面会用到) 2.右键计算机→属性→高级系统设置→高级→环境变量,在系统变量部分新建名为"JAV ...
 - Visionpro学习笔记 :QuickBuild-Based Application Run-Once Button
			
1) Creating a Run-Once Button 通过JobManager调用VisionPro文件.所有的过程放到一个Try/Catch块中. Private Sub RunOnceBut ...
 - Base64图片编码优化
			
通过对图片进行base64编码,将base64(或其他数据)内嵌在image标签的属性当中(或者CSS中或JavaScript中),可以实现将图片直接嵌入代码中的目的,如此一来,可以减少HTTP请求, ...
 - 【转】sed & awk常用正则表达式
			
正则表达式元字符 正则表达式中有两种基本元素: 以字面值或变量表示的值(如.代表任意单个字符). 操作符(如*代表将前面的字符重复任意次). 元字符汇总 特殊字符 用途 . 匹配除换行符以外的任意单个 ...
 - all,any函数
			
all函数:当矩阵全为非零元素时返回1,否则(存在零元素),返回0: any函数:当矩阵中存在非零 1 1 1 1 1 1 1 1 ...