Android中的IPC机制

IPC简介

IPC是Inter-Process Communication的缩写,含义就是进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。那么什么是进程,什么是线程,进程和线程是两个截然不同的概念。在操作系统中,线程是CPU调度的最小单元,同时线程是一种有限的系统资源。而进程指的一个执行单元,在PC和移动设备上指的是一个程序或者一个应用。一个进程可以包含多个线程,因此进程和线程是包含被包含的关系,最简单情况下,一个进程可以只有一个线程,即主线程,在Android里面也叫UI线程,在UI线程里才能操作界面元素。

那么在Android中,有特色的进程间通信方式就是Binder了,通过Binder可以轻松实现进程间通信。除了Binder,Android还支持Socket,通过Socket也可以实现任意两个终端之间的通信,当然一个设备上的两个进程之间通过Socket通信自然也是可以的。

说到IPC的使用场景就必须提到多进程,只有面对多进程这种场景下,才需要考虑进程间通信。所有运行在不同进程中的四大组件,只要它们之间需要通过内存来共享数据,都会共享失败,这也是多进程所带来的主要影响。正常情况下,四大组件中间不可能不通过一些中间层来共享数据,那么通过简单地指定进程名来开启多进程都会无法正确运行。一般来说,使用多进程会造成如下几方面的问题:

  • 静态成员和单例模式完全失效
  • 线程同步机制完全失效
  • SharedPreferences的可靠性下降
  • Application会多次创建

为了解决这个问题,系统提供了很多跨进程通信方法,虽然说不能直接地共享内存,但是通过跨进程通信我们还是可以实现数据交互。实现跨进程通信的方式有很多,比如通过Intent来传递数据,共享文件SharedPreference,基于Binder的Messenger和AIDL以及Socket等。

IPC基础概念介绍

Serializable接口
Serializable是Java提供的一个序列化接口,它是一个空接口,为对象标准的序列化和反序列化操作。使用Serializable来实现序列化相当简单,一句话即可。

public class User implements Serializable {
  private static final long seriaVersionUID = 519067123721295773L
}

Parcelable接口

Parcel内部包装了可序列化的数据,可以在Binder中自由传输,在序列化过程中需要实现的功能有序列化、反序列化和内容描述序列化功能有writeToParcel方法来完成,最终是通过Parcel中的一系列write方法来完成的。用法如下:

public class MyParcelable implements Parcelable {
    // You can include parcel data types
    private int mData;
    private String mName;
    
    // We can also include child Parcelable objects. Assume MySubParcel is such a Parcelable:
    private MySubParcelable mInfo;

    // This is where you write the values you want to save to the `Parcel`.  
    // The `Parcel` class has methods defined to help you save all of your values.  
    // Note that there are only methods defined for simple values, lists, and other Parcelable objects.  
    // You may need to make several classes Parcelable to send the data you want.
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(mData);
        out.writeString(mName);
        out.writeParcelable(mInfo, flags);
    }

    // Using the `in` variable, we can retrieve the values that 
    // we originally wrote into the `Parcel`.  This constructor is usually 
    // private so that only the `CREATOR` field can access.
    private MyParcelable(Parcel in) {
        mData = in.readInt();
        mName = in.readString();
        mInfo = in.readParcelable(MySubParcelable.class.getClassLoader());
    }

    public MyParcelable() {
        // Normal actions performed by class, since this is still a normal object!
    }

    // In the vast majority of cases you can simply return 0 for this.  
    // There are cases where you need to use the constant `CONTENTS_FILE_DESCRIPTOR`
    // But this is out of scope of this tutorial
    @Override
    public int describeContents() {
        return 0;
    }

    // After implementing the `Parcelable` interface, we need to create the 
    // `Parcelable.Creator<MyParcelable> CREATOR` constant for our class; 
    // Notice how it has our class specified as its type.  
    public static final Parcelable.Creator<MyParcelable> CREATOR
            = new Parcelable.Creator<MyParcelable>() {

        // This simply calls our new constructor (typically private) and 
        // passes along the unmarshalled `Parcel`, and then returns the new object!
        @Override
        public MyParcelable createFromParcel(Parcel in) {
            return new MyParcelable(in);
        }

        // We just need to copy this and change the type to match our class.
        @Override
        public MyParcelable[] newArray(int size) {
            return new MyParcelable[size];
        }
    };
}

Serializable和Parcelable区别
Serializable是Java中的序列化接口,其使用起来简单但是开销很大,在序列化和反序列化过程中需要大量的I/O操作。而Parcelable是Android中的序列化方式,因此更适合用在Android平台上,它的缺点就是使用起来稍微麻烦点,但是它的效率很高。

Binder
直观来说,Binder是Android中的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在Linux中没有。从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager等等)和相应ManagerService的桥梁。从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。

Binder工作机制

Android中的IPC方式

使用Bundler
我们知道,四大组件中三大组件(activity、service、receiver)都是支持在Intent中传递Bundle数据的,由于Bundle实现了Parcelable接口,所以它可以方便地在不同的进程间传输。

使用文件共享
共享文件也是一种不错的进程间通信方式,两个进程间通过读/写同一个文件来交换数据,比如A进程把数据写入文件,B进程通过读取这个文件来获取数据。

使用Messenger
Messenger可以翻译为信使,顾名思义,通过它可以在不同进程中传递Message对象,在Message中放入我们需要传递的数据,就可以轻松地实现数据的进程间传递。Messenger是一种轻量级的IPC方案,它的底层实现是AIDL,实现Messenger有以下两个步骤,分为服务端进程和客户端进程。

Messenger工作原理

使用AIDL
远程服务跨进程通信的一种方式。

使用ContentProvider
ContentProvider是Android中提供的专门用于不同应用间进行数据共享的方式,它的底层实现同样也是Binder。

使用Socket
Socket也称为“套接字”,是网络通信中的概念,它分为流式套接字和用户数据套接字两种,分别应于网络的传输控制层中的TCP和UDP协议。

选用合适的IPC方式

不同IPC方式比较

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

推荐阅读更多精彩内容