Android IPC多进程介绍

注意:本篇文章是本人阅读相关文章所写下的总结,方便以后查阅,所有内容非原创,侵权删。

本篇文章内容来自于:
Android开发艺术探索

目录

  1. 什么是IPC
  2. Android中的多进程模式
    2.1 如何开启多进程模式
    2.2 多进程模式的坏影响(为什么会有各种跨进程通信方式)
  3. IPC基础概念
    3.1 Serializable接口
    3.2 Parcelable接口
    3.3 Binder接口

1. 什么是IPC

IPC(Inter-Process Communication),进程间通信/跨进程通信,指两个进程之间进行数据交换。

进程和线程的区别
线程:线程是CPU调度的最小单元,同时线程是一种有限的系统资源。
进程:进程一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用。
一个进程可以包含多个线程,因此进程和线程是包含和被包含的关系。

Android的进程通信方式
通过Binder可以实现进程间的通信。
通过Socket可以实现两个终端之间的通信。

使用多进程的场景(2种)
场景一:
一个应用因为某些原因自身需要采用多进程模式来实现。
比如有些模块由于特殊原因需要运行在单独的进程中。
比如为了加大一个应用可使用的内存所以需要通过多进程来获取多份内存空间。Android为单个应用使用的最大内存做了限制,
场景二:
当前应用需要向其他应用获取数据,因为是2个应用,则必须采用跨进程的方式来获取所需的数据;
甚至我们通过系统提供的ContentProvider去查询数据的时候,也是一种进程间通信,只不过通信细节被系统内部屏蔽了。

2. Android中的多进程模式

2.1 如何开启多进程模式

多进程:一个应用中存在多个进程。

2.1.1 方法一:
通过四大组件指定android:process属性,则可开启多进程模式。

        <activity android:name=".DemoActivity" 
            android:process=":remote"/>
        <activity android:name=".HelloActivity"
            android:process="com.xl.haha">
  • DemoActivity启动时,系统会为它创建一个新的进程,进程名为"com.xl.demo:remote"。(假设当前包名为"com.xl.demo")
  • HelloActivity启动时,进程名为"com.xl.haha"
  • 没有指定process属性的四大组件,则运行在默认进程,进程名为包名

android:process=":remote"与"com.xl.haha"的区别
区别一:
":remote"的":"含义是指当前的进程名前面加上当前的包名,是简写。
"com.xl.haha"是完整的命名方式。
区别二:
":remote"是当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中。
"com.xl.haha"是全局进程,其他应用通过shareUID方式可以和它跑在同一个进程中。

Android系统会为每个应用分配一个唯一的UID,具有相同UID的应用才能共享数据。
两个应用通过shareUID跑在同一个进程中是有要求的,需要2个应用有相同的shareUID并且签名相同才可以。
此时,他们可以互相访问彼此私有数据(data目录、组件信息等),不管他们是否跑在同一个进程中。

2.1.2 方法二:
通过JNI在native层去fork一个进程。

2.2 多进程模式的坏影响

多进程带来的影响:不同进程中的四大组件不可以通过内存来共享数据。
因为android为每个应用/每个进程分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,导致在不同的虚拟机访问同一个类的对象会产生多个副本。

总而言之
使用多进程会造成如下几方面的问题:
1.静态成员和单例模式完全失效
2.线程同步机制完全失效
3.sharepreferences的可靠性下滑。
4.application会多次重建。

为了解决这个问题,虽然不能直接地共享内存,但是系统提供很多跨进程通信方法来实现数据交互。
跨进程通信方式有:
通过Intent来传递数据
共享文件和sharedPreferences
基于Binder的Messenger和AIDL 单方面的客户端向服务端推消息用AIDL
Socket 两者互通用Socket

3. IPC基础概念

Serializable和Parcelable可以完成对象的序列化过程。

  • 当我们需要用Intent或者Binder传输数据时需要使用Parcelable或Serializable
  • 我们需要将对象持久化到设备上或者通过网络传输时,需要用Serializable完成对象持久化

3.1 Serializable接口

使用Serializable来序列化:
只需要这个类实现Serializable接口并声明一个serialVersionUID(不是必须的)即可

//User类
public class User implements Serializable{
    private static final long serialVersionUID = 3983908423L;
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    ...
}

//实现序列化
        User user = new User("a", 1);
        File dir = Environment.getExternalStorageDirectory();
        File file = new File(dir, "haha.txt");
        //序列化  
        try {
            FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(user);
            oos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //反序列化  
        try {
            FileInputStream fis = new FileInputStream(file);
            ObjectInputStream ois = new ObjectInputStream(fis);
            User user1 = (User) ois.readObject();
            Log.d("xl", user1.toString());
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

关于serialVersionUID
serialVersionUID用于辅助序列化和反序列化过程的。
序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常的反序列化。

serialVersionUID的详细工作机制:
序列化的时候系统会把当前类的serialVersionUID写入序列化的文件中,当反序列化的时候系统会去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致。
如果一致则说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化;否则则说明当前类和序列化的类相比发生了某些变换(比如成员变量的数量、类型发生变化),则无法正常反序列化。
建议手动赋值,在很大程度上避免反序列化的失败。

3.2 Parcelable接口

只需要实现这个接口即可。

public class User implements Parcelable{
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    protected User(Parcel in) {
        name = in.readString();
        age = in.readInt();
    }

    //反序列化
    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    //内容描述
    @Override
    public int describeContents() {
        return 0;
    }

    //序列化
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
    }
}

关于Parcel
Parcel内部包装了可序列化的数据,

选择Parcelable还是Serializable?
Serializable是Java中的序列化接口,使用简单但开销大,序列化和反序列化需要大量IO操作。
Parcelable是Android中的序列化方式,更适合用于Android,只是操作麻烦,但效率高,是Android推荐的序列化方式。
因此首选Parcelable。
Parcelable主要用在内存序列化上。
将对象序列化到存储设备或者网络传输用Serializable

3.3 Binder接口

Binder是Android的一个类,实现了IBinder接口。

public class Binder implements IBinder {
3.3.1 什么是Binder
  • 从IPC角度来说,Binder是Android中的一个跨进程通信方式
  • 可以理解为一种虚拟的物理设备,设备驱动是/dev/binder,该通信方式linux中没有。
  • 从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager等)和相应ManagerService的桥梁。
  • 从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService时,服务端返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。

Binder主要用于Service中,包括AIDL和Messenger。
其中普通Service中的Binder不涉及进程间通信。
Messenger的底层其实是AIDL。

3.3.2 Binder的使用以及工作机制

ALDL示例(Binder的使用):
Android:如何创建一个AIDL

完成创建后,SDK会自动生成AIDL所对应的Binder类。
在build/generated/source/aidl/你的 flavor/ 下。


Binder的工作机制

使用时,当调用相应的接口方法getBookList(),
则会先调用Stub的getBookList()方法
该方法首先创建该方法的输入型和输出型Parcel对象_data、_reply 和返回值对象,
将方法参数写入_data,再调用transact方法来发起RPC请求,同时当前线程挂起。
然后服务端的onTransact方法会被调用。
直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程返回结果。
当服务端的onTransact方法被调用
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
服务端通过code来确定所请求的目标方法。从data中取出目标方法需要的参数,然后执行目标方法。
目标方法执行完,则往reply中写入返回值。

3.3.3 Binder的重连机制

Binder运行在服务端,如果服务端进程由于某种原因异常停止,这个时候我们服务端的Binder连接断裂(Binder死亡),会导致我们的远程调用失败。

Binder的2个很重要的方法linkToDeath和unlinkToDeath
通过linkToDeath可以给Binder设置一个死亡代理,当Binder死亡时,我们会收到通知,可以重新发起请求从而恢复连接。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358

推荐阅读更多精彩内容

  • Android跨进程通信IPC整体内容如下 1、Android跨进程通信IPC之1——Linux基础2、Andro...
    隔壁老李头阅读 11,856评论 6 38
  • 一、IPC简介 (1)IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨...
    遥遥的远方阅读 7,222评论 0 3
  • 一、Android IPC简介 IPC是Inter-Process Communication的缩写,含义就是进程...
    SeanMa阅读 1,824评论 0 8
  • 多进程概念和多进程开发模式中常见问题 Android序列化机制和Binder 详细介绍Bundle、文件共享、AI...
    Danny_yy阅读 754评论 0 1
  • 朋友的黑猫警长和呆呆狸 黑猫警长的品种是中华田园猫,但是由于外貌的特定,又名乌云踏雪。
    潘达说阅读 149评论 0 0