《Android开发艺术探索》第二章IPC机制小结

1. 通过android:process开启新的进程

进程名以“:”开头的属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中,

不以冒号开头的为全局进程,其他应用可以通过ShareUID方式可以和它跑在同一个进程中。要求ShareUID相同且签名相同,可以访问对方的私有数据,如data目录、组建信息等。同一个应用的多进程,相当于两个不同的应用采用了ShareUID的模式。


2. Serializable接口

配合serialVersionUID使用,自动序列化和反序列化;静态成员和transient关键字成员不参加序列化过程;


3. Parcelable接口

实现Parcelable接口,即实现writeToParcel(Parcel out, int flags)和Parcel.Creator中的createFromParcel;


4. Binder

可以理解为一种虚拟的物理设备,驱动是/dev/binder,通过ServiceManager连接AMS、WMS;

客户端发起请求时,当前线程会被挂起直到服务器端进程返回数据,所以耗时的远程方法不能在UI线程中调用;服务端的Binder运行在Binder的线程池中,所以不管是否耗时都应该采用同步的方式实现;


5. 手动实现一个Binder的步骤:

1)继承IInterface接口IXXXXInterface,加入业务方法和方法id,DESCRIPTOR;

2)创建Stub类,即继承Binder并实现IXXXXInterface接口,在Service的onBind方法中返回该对象

3)创建Proxy类,即实现IXXXXInterface,内涵IBinder类型的mRemote对象

4)linkToDeath可以在Binder死亡时收到通知,重新绑定远程Service


6. SharePreferences

通过键值对存储数据,底层采用XML,保存在/data/data/package name/shared prefs目录下,不建议在多进程中使用。


7. Messenger

服务端创建一个Service来处理客户端请求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messager对象底层的Binder即可。

客户端首先绑定服务端Service,之后用服务端返回的IBinder创建一个Messenger发送Message来与服务器通信;

客户端还可以创建一个新的Messenger并把它通过Message的replyTo参数传递给服务器,服务端通过replyTo可以和客户端通信。

Message中能使用的载体只有what, arg1, arg2, Bundle以及replyTo,自定义的Parcelable对象在Message的object字段无法跨进程传递。

Messager是以串行方式处理客户端发来的消息,如果大量的消息同时发送到服务端,服务端只能一个个处理;


8. AIDL

建议把所有和AIDl相关的类和文件全部放倒同一个包中,当客户端是另一个应用时可以直接把整个包复制到客户端工程中,使得包结构保持一致;

CopyOnWriteArrayList和ConcurrentHashMap支持并发读写,AtomicBoolean原子变量,

1)服务端创建Service监听客户端的连接请求,创建AIDL文件并实现相关方法;

2)客户端绑定Service,通过返回的IBinder调用AIDL定义的相关方法;

3)客户端实现一个IXXXXInterface.Stub类,生成本地Binder,然后传到Service端,Service端回调这个客户端Stub类的相应方法,客户端用Handler将回调方法转到主线程中处理

4)使用RemoteCallbackList来删除跨进程listener的接口,RemoteCallbackList<E extends IInterface>, mCallbacks = new ArrayMap<IBinder, Callback>,当客户端进程中止后,它能自动移除客户端所注册的listener,内部还实现了线程同步。用beginBroadcast和finishBroadcast来遍历。

5)客户端的onServiceConnected和onServiceDisconnedted方法都在UI线程中,服务端运行在Binder线程中;

6)服务端进程意外停止,可以给Binder设置DeathRecipient监听,收到binderDied回调(Binder线程)重连远程服务,或者在onServiceDisconnected中(UI线程)重连;


9. AIDL的权限验证

1)在AndroidMenifest中声明所需权限

<permission android:name="com.aaa.bbb.permission.ACCESS_BOOK_SERVICE" android:protectionLevel="normal" />

在Service的onBind方法直接返回(Stub)mBinder之前调用checkCallingOrSelfPermission("com.aaa.bbb.permission.ACCESS_BOOK_SERVICE"),

内部应用想绑定到Service中,<uses-permission android:name="com.aaa.bbb.permission.ACCESS_BOOK_SERVICE" />

2)在服务器端的onTransact方法中进行验证,可采用权限或者Uid和Pid,获取包名。

覆盖onTransact,调用checkCallingOrSelfPermission验证权限,调用getPackageManager().getPackagesForUid(getCallingUid())获得包名;

3)通过android:permission验证


10. ContentProvider


11. 使用Socket

1)权限声明

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

不能在主线程访问网络

2)当Service启动时,会在线程中建立TCP服务(ServerSocket),监听8868端口,然后等待客户端的连接请求。客户端连接后会生成一个新的Socket(调用ServerSocket.accept()创建),并开启新线程处理不同的客户端请求(BufferedReader读,PrintWriter写)。客户端断开时服务端会关闭相应的Socket(因为客户端断开后,服务端的输入流回返回null)。

3)客户端在自线程中创建Socket连接8688端口,在while循环中读取服务器端消息;


12.Binder连接池,将所有的AIDL放在同一个Service中处理

1)定义一个AIDL接口IBinderPool,里面有个IBinder queryBinder(int binderCode)方法,根据不同的binderCode,返回不同的Stub的实现类的binder本地对象,这些实现类分别实现了自己的AIDL接口方法;

2)Service端创建IBinderPool的本地对象,在onBind中返回;

3)客户端实现一个BinderPool单例类,调用bindService获取IBinderPool,然后提供queryBinder(int binderCode),内部调用IBinderPool的queryBinder方法;

4)客户端的Activity在自线程中调用BinderPool的queryBinder,因为BinderPool中用了CountDownLatch,将异步操作转成了同步操作。


发布了20 篇原创文章 · 获赞 2 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章