【Android 笔记】IPC 机制
两种用到 IPC 的场景
- 应用本身需要使用多个进程来实现。 如某些应用需要的内存太大,而系统分配给每个进程的内存有限,所以采用多进程获取更多内存。
- 应用向其他应用获取需要的数据。 如常见的获取通讯录信息、短信验证码等。
实现 IPC 的方式
- Intent 附带数据传递
- 共享文件
- Messenger
- Binder
- ContentProvider
- Socket
Intetent 实现
使用 Intetent 启动 Activity、Service、Receiver 可以启动其他进程,然后在其中附带数据即可。 传递的数据必须能够被序列化,即基本类型、实现了 Parcelable 或 Serializable 接口的对象、Android 支持的特殊对象
共享文件
两个进程共同读写一个文件,实现数据传输。此种方式对数据的格式没有要求。如果存在并发读写,应该注意同步问题
另外,SharedPreferences 也可以用来进行数据共享,它也属于文件的一种。需要注意的是 SharedPreferences 会在内存中缓存一份,所以得到的文件可能不是最新的。
Messenger 实现
使用 Messenger 也可以实现进程间的通信,它的底层是以 AIDL 实现。
服务端进程:创建 Handle 对象处理客户端数据,然后生成用其生成 Messenger 对象,在 onBinder() 中返回 Messenger 对象的 Binder。
客户端进程:创建 ServiceConnection 对象,向服务端发送数据。为了能接受服务的发送到客户端的数据,还需创建一个 Handler 对象来处理,并生成 Messenger 对象,然后把 Messenger 对象发送给服务端。
Service:
public class MyService extends Service {
public final static int RECEIVE_WHAT = 0;
public final static int REPLY_WHAT = 1;
private Messenger mReplyMessenger;
private Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
Log.v("_v", "service handleMessage");
switch (msg.what) {
case RECEIVE_WHAT:
Log.v("_v", "客户端消息 " + msg.getData().getString("msg"));
mReplyMessenger = msg.replyTo;
Message message = Message.obtain();
message.what = REPLY_WHAT;
Bundle bundle = new Bundle();
bundle.putString("msg", "我是服务端!!");
message.setData(bundle);
try {
mReplyMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
});
@Override
public IBinder onBind(Intent intent) {
Log.v("_v", "service onBind");
return mMessenger.getBinder();
}
}
客户端:
public class MainActivity extends AppCompatActivity {
private Messenger mMessenger;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.v("_v", "service onServiceConnected");
mMessenger = new Messenger(iBinder);
Message message = Message.obtain(null, MyService.RECEIVE_WHAT);
Bundle data = new Bundle();
data.putString("msg", "我是客服端!!");
message.setData(data);
// 将Messenger发送给服务器,以便其使用该Messenger回复
message.replyTo = mServiceReplyMessenger;
try {
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {}
};
private Messenger mServiceReplyMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
Log.v("_v", "activity handleMessage");
switch (msg.what) {
case MyService.REPLY_WHAT:
Log.v("_v", "服务器回复 " + msg.getData().getString("msg"));
break;
}
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MyService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mServiceConnection);
super.onDestroy();
}
}
AIDL 实现
ContentProvider 实现
Socket 实现
Socket 是客户端与服务器通信的一种方式,它具有和其他进程通信的功能。
Socket 有两种类型,StreamSocket(流套接字)和 DatagramSocket(用户数据报套接字),前者基于 TCP 协议,后者基于 UDP 协议。
几种方式的对比
名称 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
Bundle | 简单 | 只支持 Bundle 支持的类型 | 四大组件之间通信 |
文件 | 简单 | 不适合高并发,不能即时通信 | 无并发,数据简单,不需要即时 |
AIDL | 功能强大,高并发,即时通信 | 使用复杂,需要处理好同步 | 一对多通信 + RPC |
Messenger | 一对多通信,即时通信 | 处理不好高并发,不支持 RPC,只支持 Bundle 支持的数据 | 低并发,即时通信,无 RPC |
ContentProvider | 一对多并发,可扩展 | 受约束的 AIDL | 一对多进程间数据共享 |
Socket | 网络传输,一对多并发即时通信 | 繁琐,不支持 RPC | 网络数据交换 |