Android IPC方式解读
1.使用Bundle
由于Bundle实现了Parcelable接口,所以它可以很方便在进程之间进行传输。四大组件中的三大组件都支持在intent中传递Bundle数据的。
2.使用文件共享
共享文件也是一种进程间实现数据传输的方式,两个进程读写同一个文件就可以实现,Android是基于Linux的,所有对文件的读写可以没有限制的进行,这就可能会造成一些错误,但是通过这种方式交换数据非常简单,通过文件共享方式来交换数据是没有文件格式的要求的,只要通信双方约定好同样的格式进行转换即可。文件共享方式的局限性在于高并发情况下的读写有可能会出现问题,文件共享方式适合在对数据同步性要求不高的场景下使用。
3.使用Messenger
Messenger翻译为信使,通过它可以在不同的进程之间传递Message对象,在Message中放入我们需要传递的数据,这样可以轻松的实现数据在进程间的交换,Messenger是一种轻量级的IPC方案,他的底层实现AIDL。实现一个Messenger有以下几步分为服务端和客户端:
第一步:首先我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler,并用这个Handler创建一个Messenger对象。在onBind方法中,将Messenger底层的Binder返回。
第二步:客户端中,首先要绑定服务,绑定成功以后,利用服务器端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送信息了,发送的消息类型为Message对象。
public class MessengerService extends Service {
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
String message = msg.getData().getString("data");
Log.d("MessengerService", "handleMessage: "+message);
break;
}
}
};
private Messenger messenger = new Messenger(handler);
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
public class MainActivity extends AppCompatActivity {
private final String Tag = "MainActivity";
private Messenger messenger;
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messenger = new Messenger(service);
Message message = new Message();
message.what=1;
Bundle data = new Bundle();
data.putString("data", "你好,我是客户端");
message.setData(data);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClass(MainActivity.this, MessengerService.class);
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
从上述的案例中可以看出,在Messenger中传递数据必须要通过Message。Message和Messenger都实现了Parcelabel接口,当我们需要传递对象的时候,可以通过Bundle。这个例子演示了服务器端接受客户端发来的信息,有时候我们还需要服务器端能够回复客户端,下面我们来实现具有回复功能的,代码只需要略作修改即可。
public class MessengerService extends Service {
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
String message = msg.getData().getString("data");
Log.d("MessengerService", "handleMessage: "+message);
Messenger messenger = msg.replyTo;
Message reply = new Message();
reply.what=1;
Bundle bundle = new Bundle();
bundle.putString("reply", "你的消息我已经收到,我是服务器端");
reply.setData(bundle);
try {
messenger.send(reply);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
};
private Messenger messenger = new Messenger(handler);
@Nullable
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
public class MainActivity extends AppCompatActivity {
private final String Tag = "MainActivity";
private Messenger messenger;
private Handler replyHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
String message = msg.getData().getString("reply");
Log.d("MessengerService", "handleMessage: "+message);
break;
}
}
};
private Messenger replyMessenger=new Messenger(replyHandler);
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messenger = new Messenger(service);
Message message = new Message();
message.what=1;
Bundle data = new Bundle();
data.putString("data", "你好,我是客户端");
message.setData(data);
message.replyTo=replyMessenger;
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClass(MainActivity.this, MessengerService.class);
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
Messenger的工作流程如下:
4.使用AIDL
上面我们介绍的Messenger也有一点缺点,只能串行的处理数据,如果有大量的消息发送到服务器端,只能一条一条处理,如果有大量的并发请求,那么就不合适了。很多时候我们还可能需要调用服务器端的方法,但是Messenger只能用来传递数据。这种情况下,我们使用AIDL,下面介绍AIDL怎么实现进程间的通信,分为服务器端和客户端两个方面。
1.服务器端
需要创建一个Service用来监听客户端的请求,然后创建一个AIDL,将暴露给客户端的方法在其中声明,并在Service中实现该AIDL接口。
2.客户端
客户端端首先要绑定服务,绑定成功以后,将服务器端的Binder转换成AIDL接口所对应的类型即可,接着就可以调用AIDL中的方法了。
具体请看实现请看另外一篇博客
一个简单的AIDL实例
5.ContentProvider
6.Scoket
使用Scoket实现多进程通信方法比较简单,实现方式请查看我的这篇博客
Socket通信