IPC机制—Inter-Process Communication(一)
《Android开发与探索》
一、Android中的多进程模式
<activity
.....
android:process=":remote"
.....
/>
<activity
.....
android:process="com.xxxx.romte"
.....
/>
以":“开头属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中
不以”:"开头属于全程进程,其他应用通过ShareUID方式可以和它跑在同一个进程中
1.使用多进程会造成一些问题
a.静态成员和单例模式完全失效
b.线程同步机制完全失效
c.SharedPreferences的可靠性下降
d.Application会多次创建
关于b,解释如下:
不同进程锁的不是同一个对象了
关于c,解释如下:
SharedPreferences 底层通过读写xml来实现,并发写会出问题
关于d,解释如下:
在多进程模式中,不同进程的组件会拥有的虚拟机、Application以及内存空间
2.对象实现序列化并通过Intent和Binder传递
(1)Serializable接口
实现该接口并声明一个serialVersionUID即可进行序列化和反序列化
serialVersionUID的工作机制 p43
(2)Parcelable接口
p45
实现Parcelable步骤
1)implements Parcelable
2)重写writeToParcel方法,将你的对象序列化为一个Parcel对象,即:将类的数据写入外部提供的Parcel中,打包需要传递的数据到Parcel容器保存,以便从 Parcel容器获取数据
3)重写describeContents方法,内容接口描述,默认返回0就可以
4)实例化静态内部对象CREATOR实现接口Parcelable.Creator
3.Binder的使用及浅层原理(不讨论底层)
【理解不到位,后面要重看。。。】
binder浅析可以参考:https://www.cnblogs.com/hustzhb/p/7103361.html?utm_source=tuicool&utm_medium=referral
4.Android中的IPC方式
a.bundle
b.SharedPreferences【不建议】
c.Messenger【轻量级IPC,底层是AIDL】
d.AIDL
e.ContentProvider
f. Socket【不建议】
关于a:
我们可以在bundle中附加我们需要传输给远程进程的信息并通过Intent发送过去。当然传输的数据必须能够被序列化。
关于b:
高并发的读/写的情况下不可靠。不建议在进程间的通信中使用SharedPreferences
关于c:
在Messenger中放入数据,然后在不同进程中传递Message对象;
服务端创建一个Service处理连接,创建一个Handler并通过它去建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的binder
...
...
...
注册service
<service
android:name="xxxx.xxxx.xxxx"
android:process=":remote"
...
/>
客户端首先绑定服务端的Service,然后用服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息了
...
...
...
Messenger的工作原理
关于d:
以下大部分为转载:
https:///amurocrash/article/details/48714607
1>AIDL文件支持的数据类型如下:
(1)基本数据类型;
(2)String和CharSequence;
(3)List只支持ArrayList,里面每个元素都必须被AIDL支持;
(4)Map只支持HashMap,里面每个元素都必须被AIDL支持(包括key和value);
(5)Parcelable;
(6)AIDL接口本身;
2>服务端可以使用CopyOnWriteArrayList和ConcurrentHashMap来进行自动线程同步,客户端拿到的依然是ArrayList和HashMap;
3>服务端和客户端之间做,服务端需要使用RemoteCallbackList,否则客户端的无法收到通知
4>客户端调用远程服务方法时,因为远程方法运行在服务端的binder线程池中,同时客户端线程会被挂起,所以如果该方法过于耗时,而客户端又是UI线程,会导致ANR,所以当确认该远程方法是耗时操作时,应避免客户端在UI线程中调用该方法。同理,当服务器调用客户端的listener方法时,该方法也运行在客户端的binder线程池中,所以如果该方法也是耗时操作,请确认运行在服务端的非UI线程中。另外,因为客户端的回调listener运行在binder线程池中,所以更新UI需要用到handler。
5> 客户端通过IBinder.DeathRecipient来监听Binder死亡,也可以在onServiceDisconnected中监听并重连服务端。区别在于前者是在binder线程池中,访问UI需要用Handler,后者则是UI线程。
6>可通过自定义权限在onBind或者onTransact中进行权限验证。
关于e:
1)ContentProvider专门用于不同应用进行数据共享
2)自定义一个ContentProvider要继承并实现6个方法
----onCreate(做初始化工作)
----query
----update
----insert
----delete
----getType(返回一个Uri请求所对应的MIME类型,如果应用不关心这个,就直接返回null或" * / * ")
剩下4个就是CRUD操作了;
除了onCreate在主线程中,其他都由外界回调并运行在Binder线程池中;
3)注册provider
<provider
android:name="xxxx"
android:authorities="xxxx"
android:permission="xxx"
android:process="xxxx">
</porvider>