下面是我这篇博文的学习脑图,方便读者更快的找到自己想要了解的知识点。 看到这里,需要先了解一下进程、线程以及它们的关系。 进程:一般指一个执行单元,在PC和移动设备上指一个程序或应用。 线程:CPU调度的最小单元。线程是一种有限的系统资源。 二者之间的关系: 一个进程可包含多个线程,即一个应用程序上可以同时执行多个任务。 注意:不可在主线程做大量耗时操作,会导致ANR(应用无响应)。 进程间通信的必要性 所有运行在不同进程的四大组件,只要它们之间需要通过内存在共享数据,都会共享失败。这是由于Android为每个应用分配了独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这会导致在不同的虚拟机中访问同一个类的对象会产生多份副本。 使用Bundle、文件共享、 进程名的默认规则: 默认进程: 以“:”开头的进程: 完整命名的进程: 两个应用通过 Android为每一个进程分配了一个独立的虚拟机,不同虚拟机在内存分配上有不同的地址空间,这也导致了不同虚拟机中访问同一个对象会产生多份副本。 一般来说使用多进程会带来以下四个方面的问题: 静态变量和单例模式失效 原因:不同虚拟机中访问同一个对象会产生多份副本。 线程同步机制失效 原因:内存不同,线程无法同步。 Application多次创建- 原因:Android系统会为新的进程分配独立虚拟机,相当于应用重新启动了一次。 为了解决这些问题,可以采用跨进程通信方法,通过Intent,共享文件和 在了解以下三种接口使用前,需要先了解一下什么是序列化和反序列化。 1.什么是序列化? 含义:序列化表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。 场景:需要通过 两种方式:实现 2.什么是反序列化? 把字节序列恢复为对象的过程称为对象的反序列化,与序列化相反。 用法:实体类实现 注意: 代码示例: 用法: 实体类实现 内容描述 序列化 反序列化 代码示例: Android系统是基于Linux内核的,Linux已经提供了管道、消息队列、内存共享和 在不同的进程之间,消息发送方将要发送的数据存放在内存缓存区中,通过系统调用进入内核态。然后内核程序在内核空间分配内存,开辟一块内核缓存区,调用 各种 首先,一个进程使用 这里参考自:写给 Android 应用工程师的 Binder 原理剖析 问:当服务端进程异常终止的话,造成 在客户端绑定远程服务成功后,给 概念:由于 扩展使用:A进程要启动B进程并把在A进程计算完的数据传递给B进程,如何把不支持Bundle的数据由A进程传入B中? 答:将原本在A进程的计算任务转移到B进程的后台Service中去执行。通过 概念:两个进程通过读/写同一个文件来交换数据。 概念:可以在不同进程中传递 底层实现:轻量级的 实现 1.服务端进程 2.客户端进程 注意:除了基本数据类型,其它类型的参数必须标上方向: 返回对象: 客户端: 服务端: 解决客户端频繁调用服务器方法导致性能极大损耗的办法:实现观察者模式。 即当客户端关注的数据发生变化时,再让服务端通知客户端去做相应的业务处理。 需要用到 注意: 除了 一个 服务端: 客户端: 各种 可以将所有的 每个业务模块创建自己的 实现方式: 本文参考: 《Android开发艺术探索》
前言
IPC是什么?IPC?IPC?
一、
IPC简介1.1什么是
IPCIPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。

IPC不是Android中所独有的,任何一个操作系统都需要有相应的IPC机制,Binder是Android中最有特色的进程间通信方式。1.2为什么要进行
IPC1.3怎么进行
IPCMessenger、AIDL、ContentProvider、Socket。二、Android 中的多进程模式
2.1开启进程
AndroidMenifest中给四大组件指定属性android:process。JNI在native层fork一个新的进程。
android:process=":remote",表示进程名为com.example.myapplication:remote。
android:process="com.example.myapplication.remote"。**ShareUID**方式和他跑在用一个进程中。UID: Android系统会为每个应用分配一个唯一的UID,具有相同的UID才能共享数据。ShareUID跑在同一个进程中的条件:具有相同的ShareUID和签名。
2.2多进程的运行机制
SharedPreference的可靠性下降 原因:底层是通过读写XML文件实现的,发生并发问题。SharedPreferences,Messenger、AIDL和Socket等。三、
IPC基础概念Intent和Binder等传输类对象就必须完成对象的序列化过程。Serializable/Parcelable接口。3.1
Serializable接口Serializable是Java所提供的一个序列化接口,是一个空接口,为对象提供标准的序列化和反序列化操作。
Serializable接口,声明serialVesionUID。serialVesionUID非必需,但是不声明会对反序列化有影响。serialVesionUID与当前类的serialVesionUID相同才能被正常反序列化。serialVesionUID可以系统配置/手动修改。//User实体类实现Serializable接口; public class User implements Serializable { private static final long serialVersionUID = 1L; public int UserId; public String userName; public boolean isMale; public User(int userId, String userName, boolean isMale) { UserId = userId; this.userName = userName; this.isMale = isMale; } public static long getSerialVersionUID() { return serialVersionUID; } public int getUserId() { return UserId; } public void setUserId(int userId) { UserId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public boolean isMale() { return isMale; } public void setMale(boolean male) { isMale = male; } } //序列化过程 User user = new User(1,"Yuki",true); ObjectOutputStream outputStream; { try { outputStream = new ObjectOutputStream(new FileOutputStream("cache.txt")); //反序列化过程 ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt")); User newUser = (User)in.readObject(); in.close(); } catch (IOException e) { e.printStackTrace(); }catch (ClassNotFoundException e) { e.printStackTrace(); } } 3.2
Parcelable接口
Parcelable接口//User实体类实现Parcelable; public class User implements Parcelable { public int UserId; public String userName; public boolean isMale; // public Book book; public User(int userId, String userName, boolean isMale) { UserId = userId; this.userName = userName; this.isMale = isMale; } protected User(Parcel in) { UserId = in.readInt(); userName = in.readString(); isMale = in.readByte() != 0; // book = in.readParcelable(Thread.currentThread().getContextClassLoader()); } //反序列化 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]; } }; public int getUserId() { return UserId; } public void setUserId(int userId) { UserId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public boolean isMale() { return isMale; } public void setMale(boolean male) { isMale = male; } //内容描述 @Override public int describeContents() { return 0; } //序列化 @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(UserId); dest.writeString(userName); dest.writeByte((byte) (isMale ? 1 : 0)); // dest.writeParcelable(book,0); } } Parcelable方法说明
方法
功能
标记位
createFromParcel(Parcel in)从序列化后的对象中创建原始对象
newArray(int size)创建指定长度的原始对象数组
writeToParcel(Parcel dest, int flags)将当前对象写入序列化结构中,其中flags标识有两种值:0或者1,为1时标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有的情况都为0
PARCELABLE_WRITE_RETURN_VALUE
User(Parcel in)
从序列化后的对象中创建原始对象
describeContents返回当前对象的内容描述,如果含有文件描述符,返回1,否则返回0,几乎所有的情况都返回0
CONTENTS_FILE_DESCRIPTORSerializable和Parcelable比较
SerializableParcelable
Java序列化接口
Android序列化接口
使用简单
使用较麻烦
效率低
效率高
3.3 Binder
3.3.1 Binder是什么?
IBinder接口。**IPC 角度:Android中的一种跨进程通信**。Framework角度::ServiceManager连接各种Manager(ActivityManager、WindowManager等)的桥梁。3.3.2 为什么是Binder?
Socket等IPC机制,为什么Android还要提供Binder来实现IPC?
优势
描述
性能
只需要一次数据拷贝,性能上仅次于共享内存
稳定性
基于C/S架构,职责明确,架构清晰,稳定性好
安全性
为每个
APP分配UID,进程的UID事鉴别进程身份的重要标志3.3.3
Binder IPC底层通信原理3.3.3.1.其他
IPC机制完成一次进程间通信是怎么样的?copy*from*user() 函数将数据从用户空间的内存缓存区拷贝到内核空间的内核缓存区中。同样的,接收方进程在接收数据时在自己的用户空间开辟一块内存缓存区,然后内核程序调用 copy*to*user() 函数将数据从内核缓存区拷贝到接收进程的内存缓存区。
3.3.3.2
Binder IPC完成一次进程间通信又是怎么样的?
copy*from*user() 将数据 copy 到内核中的内核缓存区,由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样便完成了一次进程间的通信。
IPC方式数据拷贝次数
IPC数据拷贝次数
共享内存
0
Binder1
消息队列/管道/
Socket2
3.3.4 Binder通信过程
Binder框架定义了四个角色:Server,Client,ServiceManager以及Binder驱动。其中Server,Client,ServiceManager运行于用户空间,驱动运行于内核空间。这四个角色的关系和互联网类似:Server是服务器,Client是客户终端,ServiceManager是域名服务器(DNS),驱动是路由器。
BINDER*SET*CONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager;Server 通过驱动向 ServiceManager 中注册 Binder(Server 中的 Binder 实体),表明可以对外提供服务。驱动为这个 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用,将名字以及新建的引用打包传给 ServiceManager,ServiceManger 将其填入查找表。Client 通过名字,在 Binder 驱动的帮助下从 ServiceManager 中获取到对 Binder 实体的引用,通过这个引用就能实现和 Server 进程的通信。
Binder死亡的话,怎么办?Binder设置死亡代理,当Binder死亡的时候,我们会收到通知,从而重新发起连接请求。private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient(){ @Override public void binderDied(){ if(mBookManager == null){ return; } mBookManager.asBinder().unlinkToDeath(mDeathRecipient,0); mBookManager = null; // TODO:这里重新绑定远程Service } } mService = IBookManager.Stub.asInterface(binder); binder.linkToDeath(mDeathRecipient,0); 四、Android中的
IPC模式4.1
BundleBundle实现了Parcelable接口,可以方便的在不同进程间传输。
Activity、Service、Receiver间传递。Intent发送。Intent启动B进程的一个Service,让计算任务在Service完成,计算完成 后再去启动目标组件,并把数据传递给目标组件。4.2 文件共享
4.3
MessengerMessage对象,把需要传递的数据放进对象中。
IPC 方案,它的底层实现是 AIDL。Message
Service处理客户端连接请求Handle并通过它创建一个Messenger对象Service的onBind返回这个对象的底层Binder
ServiceIBinder对象创建一个Messenger(客户端——>服务端)Handler并由此创建一个Messenger,并通过Message的**replyTo字段**传递给服务器端进程。服务端通过读取Message得到Messenger对象,进而向客户端进程传递数据。(客户端 <——>服务端)//Messenger 服务端代码 public class MessengerService extends Service { private static final String TAG = "MessengerService"; private final Messenger messenger = new Messenger(new MessengerHandler()); //处理客户端发送的消息 private static class MessengerHandler extends Handler{ @Override public void handleMessage(@NonNull Message msg) { switch (msg.what){ case 1: Log.i("TAG"," "+msg.getData().getString("msg")); break; default: break; } super.handleMessage(msg); } } @Nullable @Override public IBinder onBind(Intent intent) { return messenger.getBinder(); //返回它的Binder对象 } } <service android:name=".MessengerService" android:process=":remote"/> //注册Service //客户端代码 public class MessengerActivity extends AppCompatActivity { private Messenger mService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //绑定服务 Intent intent = new Intent(this,MessengerService.class); bindService(intent,mConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = new Messenger(service); //用服务端返回的IBinder对象创建一个Messenger对象 Message msg = Message.obtain(null,1); Bundle data = new Bundle(); data.putString("msg","Client"); msg.setData(data); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onDestroy() { unbindService(mConnection); super.onDestroy(); } } 
4.4 使用
AIDLAIDL 是 Android Interface Definition Language 的缩写,意思是Android接口定义语言,用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。其使用可以简单的概括为服务端和客户端,类似于Socket 一样,服务端服务于所有客户端,支持一对多服务。4.4.1
Messenger和AIDL比较Messenger缺点:串行方式处理消息,无法并发处理。AIDL:可以并发处理请求。AIDL通信流程
Service监听客户端请求AIDL文件AIDL文件中申明暴露给客户端的接口Service实现这个AIDL接口AIDL接口所属的类型AIDL方法4.4.2
AIDL能够支持哪些数据类型?
in、out或inout,用于表示在跨进程通信中数据的流向。4.4.3 关键类和关键方法
AIDL接口:继承IInterface。Stub类:Binder的实现类,服务端通过这个类来提供服务。Proxy类:服务器的本地代理,客户端通过这个类调用服务器的方法。asInterface():客户端调用,将服务端的返回的Binder对象,转换成客户端所需要的AIDL接口类型对象。
Stub对象本身;Stub.proxy对象。
asBinder():返回代理Proxy的Binder对象。onTransact():运行服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。transact():运行在客户端,当客户端发起远程请求的同时将当前线程挂起。之后调用服务端的onTransact()直到远程请求返回,当前线程才继续执行。4.4.4 产生
ANR的情形
Binder线程池中,若主线程所调用的方法里执行了较耗时的任务,同时会导致客户端线程长时间阻塞,易导致客户端ANR。onServiceConnected()和onServiceDisconnected()里直接调用服务端的耗时方法,易导致客户端ANR。
Binder线程中,可在其中执行耗时操作,而无需再开启子线程**。Listener的方法是运行在客户端的Binder线程中,若所调用的方法里执行了较耗时的任务,易导致服务端ANR。4.4.5解注册失败的问题
Binder进行对象传输实际是通过序列化和反序列化进行,即Binder会把客户端传递过来的对象重新转化并生成一个新的对象,虽然在注册和解注册的过程中使用的是同一个客户端传递的对象,但经过Binder传到服务端后会生成两个不同的对象。另外,多次跨进程传输的同一个客户端对象会在服务端生成不同的对象,但它们在底层的Binder对象是相同的。Listener,找到和解注册Listener具有相同的Binder对象的服务端Listener,删掉即可。RemoteCallBackList:Android系统专门提供的用于删除跨进程listener的接口。其内部自动实现了线程同步的功能。4.5 使用
ContentProvider4.5.1 什么是
ContentProvider?ContentProviderAndroid中提供的专门用于不同应用间进行数据共享的方法,它天生就适合进程间通信。4.5.2 如何自定义一个
ContentProvider?
ContentProvider。onCreate、query、update、insert、delete和getType等六种抽象方法。、onCreate()运行在UI线程中,其他的query()、update()、insert()、delete()和getType()都运行在Binder线程池中。CRUD四大操作存在多线程并发访问,要注意在方法内部要做好线程同步。SQLiteDatabase内部对数据库的操作有同步处理,但多个SQLiteDatabase之间无法同步。4.6 使用
Socket4.6.1 什么是
Socket?Socket也称为“套接字”,是网络通信的概念。分为流式套接字和用户数据报套接字两种。
TCP协议,采用流的方式提供可靠的字节流服务。UDP协议,采用数据报文提供数据打包发送的服务。4.6.2 怎么实现
Socket通信?
Service,在线程中建立TCP服务、监听相应的端口等待客户端连接请求;Socket对象,利用它可与客户端进行数据传输;Socket并结束线程。
Socket发出连接请求;Socket。五、
IPC方式IPC方式的优缺点比较:
名称
优点
缺点
适用场景
Bundle简单易用
只能传输Bundle支持的数据类型
四大组件间的进程间通信
文件共享
简单易用
不适合高并发场景,无法做到进程间的即时通信
无并发访问,交换简单数据且实时性不高
AIDL支持一对多并发和实时通信
使用稍复杂,需要处理线程同步
一对多且有
RPC需求
Messenger支持一对多串行通信
不能很好处理高并发,不支持
RPC,只能传输Bundle支持的数据类型低并发的一对多
ContentProvider支持一对多并发数据共享
可理解为受约束的
AIDL一对多进程间数据共享
Socket
支持一对多并发数据共享
实现细节繁琐
网络数据交换
六、
Binder连接池6.1 典型的
AIDL使用流程
Service和一个AIDL接口AIDL接口中的Stub类并实现Stub中的抽象方法onBind方法中返回这个类的对象6.2 当有多个不同的业务需要使用
AIDL来进行通信,该怎么处理?AIDL放在同一个Service中去管理,它的工作机制是这样的:AIDL接口,向服务端提供自己的唯一标识和对应的Binder对象。对服务端来说,只需一个Service,服务端提供一个queryBinder接口,可以根据业务模块特征返回相应的Binder对象。Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service去执行,避免重复创建Service。
AIDL接口并具体实现。Binder连接池创建AIDL接口IBinderPool.aidl并具体实现。BinderPoolService的实现,在onBind()返回实例化的IBinderPool实现类对象。Binder连接池的具体实现,来绑定远程服务。
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算
官方软件产品操作指南 (170)