一、基础知识
1.一些概念
IPC : Inter-process Communication 跨进程通信,是指两个进程之间进行数据交换的过程。
线程:线程是 CPU 调度的最小单元,同时线程是一种有限的系统资源。
进程:一般是指一个执行单元, 在 PC 和移动设备上指一个程序或者一个应用。 进程可以包含多个线程。
2. Android 中的多进程模式
(1).开启多进程模式
给四大组件在 AndroidManifest 中指定 android:process 属性,即可开启。
通过命令行 adb shell ps 可以看见进程信息。
(2).多进程模式的运行机制
系统会为每一个进程分配一个独立的虚拟机,不同的虚拟机在内存分配不同的地址空间。
使用多进程会造成的问题:
.静态成员和单例模式完成失效;
.线程同步机制完成失效;
.SharedPreferences 的可靠性下降;
.Application 会多次创建(因为运行同一个进程中的组件是属于同一个虚拟机和同一个 Application 的)
二、IPC 基础概念介绍
1、Serializable 接口
Serializable 是 Java 提供的一个接口,是一个空接口,为对象提供标准的序列化和反序列化操作;
serialVersionUID :
用来辅助序列化和反序列化过程的,原则上序列化后的数据中的 serialVersionUID 只有和当前类的 serialVersionUID 相同 才能正常地被反序列化。
一般手动指定 serialVersionUID 的值,是因为反序列化时当前类有所改变时,系统会重新计算当前类的 hash 值,并把它赋值 给 serialVersionUID ,这个时候当前类的 serialVersionUID 和反序列化的数据中的 serailVersionUID 不一致,会出现反序列化 失败,程序会出现 crash。
注意事项:
.静态成员变量属于类而不属于对象,所以不会参与序列化过程;
.用 transient 关键字的成员变量不参与序列化过程。
2、Parcelable 接口
Interface for classes whose instance can be written to and restored from a Parcel. Classes implementing the Parcelable interface must also have a non-null static field called CREATOR of the type implements Parcelable.Creator interface.
Serializable 与 Parcelable 的区别与选用
Serializable 开销大,序列化和反序列化过程需要大量的 I/O 操作,如果是存储在设备中,网络传输,一般使用 Serializable;
Parcelable 主要用在内存序列化上,是 Android 中的方法。
3、Binder
Binder 是 Android 中的一个类,它实现 IBinder 接口。从 IPC 的角度来说, Binder 是 Android 中的一种跨进程通讯方式。
Android 开发中, Binder 主要用在 Service 中,包括 AIDL 和 Messenger .
三、 Android 中的 IPC 方式
1、使用 Bundle
2、使用文件共享
序列化一个对象到系统文件中,同时从另一个进程中恢复这个对象。
发序列化得到的对象只是在内容上和序列化之前的对象是一样的,但它们本质上还是两个对象。
使用文件方式来共享数据对文件格式没有具体的要求,只要读写双方约定数据格式即可。但是这种方式会面临并发读写的局限性。
文件共享方式适合在对数据同步要求不高的进程之间进行通信,并且要处理并发读写的问题。
系统对 SharedPreference 的读写有一定的缓存,在多进程中,SP 面对高并发的读写访问会丢失数据,所以,尽量不要在进程间通信中使用 SP.
3、使用 Messenger
轻量级 IPC 方案,底层实现是 AIDL ,串行处理消息。
例子
服务端进程
public class MessengerService extends Service {
private static final String TAG = "message";
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case Constants.MSG_FROM_CLIENT:
Log.i(TAG, "receive msg from Client : " + msg.getData().getString("msg"));
// 回复客服端
Messenger client = msg.replyTo;
Message replyMessage = Message.obtain(null, Constants.MSG_FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString("reply", "你的消息已收到");
replyMessage.setData(bundle);
try {
client.send(replyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
public class MessengerActivity extends Activity {
private static final String TAG = "message";
private Messenger mMessenger;
private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessenger = new Messenger(service);
Message msg = Message.obtain(null, Constants.MSG_FROM_CLIENT);
Bundle data = new Bundle();
data.putString("msg", "Hello, this is client.");
msg.setData(data);
msg.replyTo = mGetReplyMessenger;
try {
mMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
Intent intent = new Intent(this, MessengerService.class);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case Constants.MSG_FROM_SERVICE:
Log.i(TAG, "receive msg from Service : " + msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
break;
}
}
}
}
4、使用 AIDL
使用 AIDL 比较复杂,这里掠过
5、使用 Socket
使用 Socket 通信,首先要声明权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
四、选用合适的 IPC 方式