Android开发艺术探索-IPC机制
16lz
2021-01-23
什么是IPC
Inter-Process Comminication 进程间通信
各平台进程间如何通信
- Windows
剪切板、管道和油槽- Linux
命名管道、共享内容和信号量- Android
基于Linux,常用Binder和Socket
Android应用如何开启多进程
- 通过给四大组件指定
android:process
- 通过JNI
在native层fork
一个新的进程不推荐
指定android:processs
- 系统将为每个进程名生成一个进程,进程名相同将运行在同一进程中
样式 | 实际进程名 |
---|---|
:remote | ${packageName}:remote |
com.a.b.remote | com.a.b.remote |
同程序多进程的危害
情况 | 原因 |
---|---|
静态成员和单例失效 | 在不同的虚拟机中 |
线程同步机制完全失效 | 锁无法保证同步,因为在不同的虚拟机中 |
线程同步机制完全失效 | 锁无法保证同步,因为在不同的虚拟机中 |
SharedPreferences数据丢失 | 多个进程对同一个文件进行读写引起 |
Application多次创建 | 每个虚拟机都会创建一次3 |
对象序列化
- Serializable : 常用于存储和网络通信
- Parcelable : 常用于内存通信,由于在内存中序列化,效率更高
- Bundle
ipc方式的优缺点和适用场景
名称 | 优点 | 缺点 | 设用场景 |
---|---|---|---|
Bundle | 简单易用 | 只能传输Bundle支持的数据类型 | 四大组件间的进程通信 |
文件共享 | 简单易用 | 不适合高并发的情况,并且无法做到进程间的即时通讯 | 无并发访问情况下,交换简单的数据实时性不高的情况 |
AIDL | 功能强大,支持一对多并发通信,支持实时通讯 | 需要处理好线程同步 | 一对多通信且有Rpc需求 |
Messager | 支持一对多串行通信,支持实时通讯 | 不能很好处理高并发情况,不支持Rpc,数据通过Message进行传输,因此只能传输Bundle支持的数据类型 | 低并发的一对多即时通信,无Rpc需求,或者无需返回结果的Rpc需求 |
ContentProvider | 在数据源访问方面功能强大,支持一对多并发数据共享,可通过call方法扩展其他操作 | 主要提供数据源的Crud | 一对多的进程间数据共享 |
Socket | 功能强大,可以通过网络传输字节流,支持一对多并发实时通讯 | 实现细节有点繁琐,不支持直接的Rpc | 网络数据交换 |
Binder各角度理解
-
IPC
是一种跨进程通信方式,也可理解为虚拟的物理设备/dev/binder
-
Android Framework
是ServiceManager连接各种Mangager的桥梁 -
应用层
是客户端和服务端进行通信的媒介AIDL
AIDL使用解析
文件共享
- 适合在数据同步要求不高的进程之间进行通信
- SharedPreference也是文件共享,但由于Android对他有一层内存缓存,所以多进程操作很容易丢失数据。
使用Messenger
- 是轻量级IPC方案,顶层使用AIDL实现
- 串行(Handler)处理请求,大量并发请求状况不适用
public class MessengerService extends Service { private static class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { // 回数据 switch (msg.what) { case 0: System.out.println(msg.getData().getString("request")); Messenger client = msg.replyTo; Message replyMsg = Message.obtain(null, 1); Bundle data = new Bundle(); data.putString("result", "i've received you request"); replyMsg.setData(data); try { client.send(replyMsg); break; } catch (RemoteException e) { e.printStackTrace(); } default: super.handleMessage(msg); } } } private final Messenger mMessenger = new Messenger(new MessengerHandler()); @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); }}
public class MainActivity extends AppCompatActivity { private Messenger mMessenger; private Messenger mGetReplyMessenger = new Messenger(new ClientMsgHandler()); private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 发数据 mMessenger = new Messenger(service); Message msg = Message.obtain(null, 0); Bundle data = new Bundle(); data.putString("request", "i'm client, send a msg"); msg.setData(data); msg.replyTo = mGetReplyMessenger; try { mMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; static class ClientMsgHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Bundle data = msg.getData(); System.out.println(data.getString("result")); break; default: super.handleMessage(msg); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(MainActivity.this, MessengerService.class); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { unbindService(mServiceConnection); super.onDestroy(); }}
AIDL跨进程回调
封装一个集合存储回调
由于跨进程对象会经过序列化和反序列化(普通集合移除时传入对象和集合中对象不同),所以需要使用
RemoteCallbackList
来避免回调对象移除失败RemoteCallbackList : 内部有个ArrayMap结构专门用来保存AIDL回调,这个Map的key是Ibinder类型,value是CallBack类型。其中CallBack中封装了真正的Listener远程对象
服务端
// IOnChangeListener.aidl 回调接口package com.rtfsc.passwordinputview;interface IOnChangeListener { void onChange(String aString);}
// IMyAidlInterface.aidl 远程服务接口package com.rtfsc.passwordinputview;import com.rtfsc.passwordinputview.IOnChangeListener;interface IMyAidlInterface { void doSomething(String str); void registerListener(IOnChangeListener listener); void unregisterListener(IOnChangeListener listener);}
// AidlService.java 远程服务Servicepublic class AidlService extends Service { private RemoteCallbackList mCallbackList = new RemoteCallbackList<>(); private Binder mBinder = new IMyAidlInterface.Stub() { @Override public void doSomething(String str) throws RemoteException { System.out.println("[email protected]" + str); } @Override public void registerListener(IOnChangeListener listener) throws RemoteException { listener.onChange("call back register"); System.out.println("[email protected]" + mCallbackList.register(listener)); } @Override public void unregisterListener(IOnChangeListener listener) throws RemoteException { listener.onChange("call back unregister"); System.out.println("[email protected]" + mCallbackList.unregister(listener)); } }; @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; }}
// AndroidManifest.xml
- 客户端
public class MainActivity extends AppCompatActivity { IMyAidlInterface iMyAidlInterface; private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); try { iMyAidlInterface.registerListener(mListener); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; private IOnChangeListener mListener = new IOnChangeListener.Stub() { @Override public void onChange(String aString) throws RemoteException { System.out.println(aString); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(MainActivity.this, AidlService.class); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { try { if (iMyAidlInterface != null) { iMyAidlInterface.unregisterListener(mListener); } } catch (RemoteException e) { e.printStackTrace(); } unbindService(mServiceConnection); super.onDestroy(); }}
- Log
07-28 18:04:24.017 6844-6844/com.rtfsc.passwordinputview I/System.out: call back register07-28 18:04:24.017 6873-6890/com.rtfsc.passwordinputview:remote I/System.out: [email protected]07-28 18:04:29.027 6844-6844/com.rtfsc.passwordinputview I/System.out: call back unregister07-28 18:04:29.027 6873-6890/com.rtfsc.passwordinputview:remote I/System.out: [email protected]
更多相关文章
- 开源项目之Android DataFramework(数据库框架)
- Android studio查看SQLIte数据库文件
- Android 数据库事务的个人理解
- 使用openFileInput和openFileOutput实现Android平台的数据存储
- [转]SimpleCursorAdapter类与数据绑定
- Android音视频 - Camera+AudioRecord采集数据
- 抖音数据采集教程,Android群控黑盒调用,Sekiro使用手册