IPC总结

IPC

这个知识点我的了解是从一本书上知道的《Android开发艺术探索》

所以我也就根据这本书来总结一下我所学到的,毕竟好记性不如烂笔头。

从头到尾说一遍估计到时候都不知道自己在说什么,所以先把问题列出来,然后带着问题来总结应该比较好一点。

那就一个问题一个问题的来

1、什么是IPC?

IPC是一个英文简写:Inter-Process Communication,可以理解为进程间通信或者跨进程通信;

2、什么是进程?

这种问题应该没什么好说的,既然都看到这了,应该都知道进程、线程、时间片的,不知道的自己看看操作系统;多说一句,没必要深入理解(当前阶段),当你需要理解的时候再去理解,只要知道这是一个什么东西就够了。相对于APP来说,一个APP一般只有一个进程(当然也有例外,可能有多个),在很久以前(也不算很久),最小的调度单元是进程,后来才添加的线程,然后这个最小就变成线程了,一个进程可以有多个线程;相对于APP来说,当你的APP在下载更新的以后,起码开了两个线程,一个UI线程,一个Service下载线程(4.0以上啊,否则会ANR,一直说4.0以上这个,其实我也没用过之前的。。。)

3、ANR是什么?

你猜

4、IPC是Android所独有的吗?

并不是;
Window:通过剪切板、管道、邮槽来进行进程间通信;
Linux:通过命名管道、共享内存、信号量来进行进程间通信;
Androidb爸爸是Linux,所以也继承了这一份基因,但是不是完全的,其中比较有特色的就是Binder,还有Socket;

5、如何开启多进程?

给四大组件指定一个属性:

android:process=""

6、如何跑到一个进程中

可以通过ShareUID的方式跑到一个进程中;每个应用都有唯一的一个UID,具有相同UID的应用可以共享数据;具有相同的ShareUID和签名可以跑到同一个进程;不同进程可以互相访问对方的私有数据,在同一进程甚至可以访问内存数据;

7、多进程造成的问题

1、静态成员和单例模式完全失效;
2、线程同步机制完全失效;
3、SharePreferences的可靠性下降;
4、Application会多次创建;

解释:

1、每个进程都分配了一个单独的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致了在不同的虚拟机中访问同一个类型对象会产生多个副本;在一个进程中修改只会影响当前进程,并不会影响其他进程。

2、锁不住同一个对象;既然都不只同一块内存了,那么不管是锁对象还是锁全局类都无法保证线程同步,因为不同进程锁的不是同一个对象;

3、SharePreferences不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失;

4、当一个组件跑到一个新的进程中的时候,由于系统要在创建新的进程同时分配独立的虚拟机,所以这个过程其实就是气筒一个应用的过程。因此,相当于系统又把这个应用重新启动了一遍,既然重启了,那么自然会创建爱你新的Application;运行在同一个进程的组件是属于同一个虚拟机和同一个Application的,同理,运行在不同进程中的组件是属于两个不同的虚拟机和Application的。

8、实现IPC(跨进程通信)的方式有哪些?

在Intent中附加extras来传递数据
共享文件
SharePreferences
基于Binder的Messenger和AIDL
Socket
ContentProvider天生就支持

9、系列化和反序列化

为什么要扯序列化和反序列化呢?因为Intent和Binder传输数据时就需要使用序列化;

10、Serializable

这个是java提供的一个空接口(作为一个标签使用的);
使用简单,实现这个接口,指定一个serialVersionUID;

这个serialVersionUID是用来辅助反序列化和序列化的,原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常的被反序列化。

比如当版本升级后,我们可能删除了某个成员变量也可能增加了一些新的成员变量,这个时候我们的反向序列过程仍然能够成功,程序仍然能够最大限度的恢复数据,相反,不指定serialVersionUID的话,程序则会挂掉。

11、Parcelable

这个是Android独有的,手写起来稍微复杂了一点,但是有自动生成工具,可以一键生成;

说是复杂,其实里面也没什么东西,无非多了几个方法;

package com.xiey94.card;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by xiey on 2018/1/15.
 */

public class User implements Parcelable {
    private int userId;
    private String userName;
    private boolean isMale;

    public User(int userId, String userName, boolean isMale) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.userId);
        dest.writeString(this.userName);
        dest.writeByte(this.isMale ? (byte) 1 : (byte) 0);
    }

    public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
        @Override
        public User createFromParcel(Parcel source) {
            return new User(source);
        }

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

    protected User(Parcel in) {
        this.userId = in.readInt();
        this.userName = in.readString();
        this.isMale = in.readByte() != 0;
    }
}

只是多了下面四个方法
Parcel:Parcel内部包装了可序列化的数据,可以在Binder中自由传输;
从上述代码中可以看出,在序列化过程中需要实现的功能有序列化、反序列化和内容描述。
序列化功能由writeToParcel方法来完成,最终是通过Parcel中的一系列write方法来完成的;
反序列化功能是由CREATOR来完成的,其内部标明了如何创建序列化对象和数组,并通过Parcel的一系列read方法来完成反序列化过程。
描述功能是由describeContents方法来完成,大部分返回0;

系统已经为我们提供了许多实现了Parcelable接口的类,他们都是可以直接序列化的:
intent、bundle、Bitmap;
List的子类ArrayList可以序列化,Map可以序列化,前提是他们的每个元素都是可以序列化的。
注意:List可以曲线救国,不停的与数组进行转换也可以序列化。

12、Binder

这个可是一条大鱼,一不小心就卡刺,我读到现在还是懵懂的。

从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,等等)和相应ManagerService的桥梁;

从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务;

Android开发中,Binder主要用于Service中,包括AIDL和Messenger,其中普通的Service中的Binder不涉及进程中通信,所以较为简单,而Maessenger的底层其实是AIDL

13、AIDL

AIDL:Android Interface Definition Language,理解为:android内部进程通信接口的描述语言;

AIDL比较复杂

这里写图片描述

只说一下:
当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法是很耗时的,那么不能在UI线程中发起此远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以Binder方法不管是否耗时都应该采用同步的方式去实现,因为他已经运行在同一个线程中了。

说了跟没说一样,主要是这一块我也很懵逼,看了好几遍还是不是太懂,也不能把书抄一遍,没什么意思,所以,暂时很抱歉。

14、Android中的IPC有哪些方式?

Bundle:他实现了Parcelable接口,可以在Bundle中附加信息,通过Intent传递;

文件共享:在一个进程中保存对象信息,然后在一个进程中恢复对象信息,本质上这两个对象不是同一个对象,他们只是内容相同;SharedPreferences是个特例,从本质上来说,SharedPreferences也属于文件的一种,但是由于系统对他的读写有一定的缓存策略,即在内存中会有一份SharedPreferences文件的缓存,因此在多进程模式下,系统对它的读写就变得不可靠,当面对高并发的读写访问,SharedPreferences有很大几率会丢失数据,因此,不建议在进程间通信中使用SharedPreferences。

Messenger:信使,可以在不同进程中传递Message对象,在Message中放入我们需要传递的数据,就可以传递了;Message中能使用的载体只有what、arg1、arg2、Bundle以及replyTo(用过Handler就应该有印象);

使用AIDL:本来是一脸懵逼,放弃写这个的,后来想想,只是被它的实现原理和流程吓到了,但是不能被他的使用给吓到啊;

分为服务端和客户端

服务端:
服务端首先要创建一个Service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现了这个AIDL接口即可。

客户端:
客户端所要做的事情就稍微简单一点,首先需要绑定服务端的Service,绑定成功后,将服务端返回的Binder对象转成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。

AIDL支持哪些类型呢:
基本数据类型
String和CharSequence
List:只支持ArrayList,里面的每个元素必须被AIDL支持,包括key和value
Map:只支持HashMap,同上
Parcelable:所有实现了Parcelable接口的对象
AIDL:所有的AIDL接口本身也可以在AIDL文件中使用
注意:
1、其中自定义的Parcelable对象和AIDL对象必须要显示import进来;
2、如果AIDL文件中用到了自定义的Parcelable对象,那么必须要新建一个和它同名的AIDL文件,并在其中声明它为Parcelable类型;
3、AIDL接口中只支持方法,不支持声明静态常量;

15、Binder意外死亡怎么办?

1、给Binder设置DeathRecipient监听,当Binder死亡时,我们会收到binderDied方法的回调,在binderDied方法中我们可以重连远程服务;
2、在onServiceDisconnected中重连远程服务;

16、ContentProvider如何使用?

ContentProvider的底层实现同样也是Binder;它内置了增删改查,可以简单使用

这个属于四大组件,是需要注册的:

android:authorities=""

是ContentProvider的唯一标识,通过这个属性外部应用就可以访问我们的ContentProvider了

具体的自己去试试;

17、如何使用Socket

套接字;
TCP:流式套接字;
UDP:用户数据报套接字;
TCP经过三次握手之后完成连接,然后稳定传输数据,而UDP是无连接的,但是传输容易丢包;

这个一般是用于通信(常见的就是聊天室类型应用,以前研究过,后来长时间没用就忘记了,不过这个对于一般的人员来说,了解就足够了,因为第三方聊天可以接入强大的第三方;隐隐约约还记得以前韩国有一个的大神写了一个比较厉害服务端加客户端,好像有客户端,可以拿过来改改做成自己的产品,不过这样我觉得除了大神一般很少有人去深入的做这个,个人浅见)

18、最后来个大总结:

IPC方式的优缺点和适用场景:

名称优点缺点适用场景
Bundle简单易用只能传输Bundle支持的数据类型四大组件间的进程间通信
文件共享简单易用不适合高并发场景,并且无法做到进程间的即时通信无并发访问情形,交换简单的数据实时性不高的场景
AIDL功能强大,支持一对多并发通信,支持实时通信使用稍麻烦,需要处理好线程同步一对多通信且有RRPC需求
Messenger功能一般,支持一对多串行通信,支持实时通信不能很好处理高并发情形,不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型低并发的一对多即时通信,无RPC需求,或者无须要返回结果的RPC需求
ContentProvider在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作可以理解为受约束的AIDL,主要提供数据源的CRUD操作一对多的进程间的数据共享
Socket功能强大,可以通过网络传输字节流,支持一对多并发实时通信实现细节稍微有点烦琐,不支持直接的RPC网络数据交换



AIDL那块实在是生疏,看了好几遍还是不能深入理解,还要专门针对AIDL好好的看一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值