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