通信方式只是一种手段,我们重点应该放在了解各种优缺点、了解底层实现原理。这里就简单总结下使用及其优缺点至于底层原理在后续的文章在进行总结吧emmm,,,
通信方式
- 使用Intent
- 使用共享文件
- Messenger
- 使用AIDl
- 使用ContentProvider
- 使用Socket
一、使用Intent
android四大组件之间的信使,开启组件时Intent可以携带一些数据这就使得Intent具有了跨进程通信的能力。其实说Intent具有跨进程通信的能力是不准确的,底层真正传递数据的是Binder,由于我们是使用Intent进行携带数据的这里就认为是一种IPC方式吧。
1、传递数据的类型
Intent 通过putXXX方式传递数据。通过getXXX方式接收数据。乍一看put方法一大堆,其实这些方法都是有规律的,传递的value值数据类型必须是实现序列化接口的。如下为简单的归纳:
1、java基本数据类型(其包装对象实现了序列化接口)
2、实现了序列化接口对象(String类、自定义类等等)
3、java Map、List的实现类(实现了序列化接口)
4、安卓中的特殊类Bundle、Bitmap等(实现了序列化接口)
2、栗子
emmm,Intent太常见了,没有栗子啦!!!!
二、使用共享文件
进程A内吧数据写入磁盘,进程B内读取磁盘数据,这样很简单就进行IPC了。这不很easy吗?这时你想了想标题是不是还心存疑惑,为啥要说共享文件呢?直接说使用文件不好吗?其实还真的不行:
安卓为每个应用分配的有私有空间(data/data/包名/),空间内的文件数据一般情况下是app间不共享的(不同的app想要共享可以通过ShareUID方式来实现),所以想要通过文件进行IPC还需要使用公用的磁盘空间(即吧文件放到公共目录下即/storage/emulated/0)。所以说使用共享文件。
1、栗子
//MainActivity 运行在主进程中
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
// data/data/包名/files/test.txt
OutputStream outputStream = openFileOutput("test",MODE_PRIVATE);
outputStream.write("简单的文件共享".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
}
}
//SecondActivity 运行在新开的进程中
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
try {
FileInputStream in = openFileInput("test");
byte[] buf= new byte[1024];
int len = 0;
while((len = in.read(buf))!=-1){
String s = new String(buf,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、使用Messenger
Messenger 这个类对AIDL进行了封装。
1、栗子
#服务端MyService
简单的客户端 发送消息,服务端接收消息
<service
android:name=".service.MyService"
android:enabled="true"
android:exported="true"
tools:remove=":remote">
</service>
public class MyService extends Service {
private Messenger messenger = new Messenger(new MyHandler());
// handler
private static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Log.i(Tags.TAG, "服务端:收到消息, " + msg.getData().get("data"));
break;
default:
super.handleMessage(msg);
break;
}
}
}
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
#客户端MainActivity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1 绑定服务
Intent intent = new Intent(this, MyService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
// 2、获得信使
Messenger messenger = new Messenger(service);//使用上面的构造2
Bundle bundle = new Bundle();
bundle.putString("data", "你好,我是MainActivity --- 客户端");
//3、准备消息
Message msg = Message.obtain();
msg.what = 1;
msg.setData(bundle);
//4、信使发送消息
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
log:
服务端回消息,客户端也接收。简单修改服务端客户端代码:
#服务端的消息处理中
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Log.i(Tags.TAG, "服务端:收到消息, " + msg.getData().get("data"));
replyMessenger = msg.replyTo;
replyMessage();// 回复消息
break;
default:
super.handleMessage(msg);
break;
}
}
/**
* 回复消息
* */
private void replyMessage() {
try {
Message message = Message.obtain();
message.what=0;
Bundle bundle = new Bundle();
bundle.putString("test","this is sever speaking");
message.setData(bundle);
replyMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
客户端:
private Messenger mMessenger = new Messenger(handler);
static Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
Log.i(Tags.TAG, "客户端:收到回复, " + msg.getData().get("test"));
break;
default:
super.handleMessage(msg);
break;
}
}
};
conn回调中吧服务端的messenger回调对象也发送过去
public void onServiceConnected(ComponentName name, IBinder service) {
try {
Messenger messenger = new Messenger(service); // 1、获得messenger 对象
Message message = Message.obtain(); //2、制作消息
Bundle bundle = new Bundle();
bundle.putString("data", "你好,我是MainActivity --- 客户端");
message.what = 1;
message.setData(bundle);
// 加1句重要代码 加1句重要代码 加1句重要代码
message.replyTo = mMessenger; //服务端回调的messenger 也发送过去
messenger.send(message); // 3、messenger 发送消息
} catch (RemoteException e) {
e.printStackTrace();
}
}
效果:
四、使用AIDL
Android IPC-AIDl
五、使用ContentProvider
跨进程通信的 ContentProvider
六、使用Socket
参考:
七、IPC优缺点与使用场景
IPC方式 | 优点 | 缺点 | 适用场景 |
Intent | 使用简单 | 只能传输实现序列化接口的对象 | 安卓四大组件的进程间通信 |
文件共享 | 使用简单 | 不适合高并发场景,无法做到进程间即时通信 | 无并发访问场景,交换简单的数据,实时性不高的数据 |
AIDL | 功能强大,支持一对多并发通信,支持实时通信 | 使用稍微复杂,需要处理好线程同步问题 | 一对多通信且有RPC |
Messenger | 功能一般,支持一对多串行通信,支持实时通信 | 不能很好处理了高并发情形,不支持RPC,数据通过Messenger进行传输,只支持Bundle支持的类型数据 | 低并发,一对多即时通信,无RPC需求,或者无需要返回结果的RPC |
ContentProvider | 在数据源访问方面功能强大,支持一对多并发数据共享,可通过call方法扩展其他操作 | 可以理解为受约束的AIDl,主要提供数据源的CURD操作 | 一对多的进程间数据共享 |
Socket | 功能强大,可以通过网络传输字节流,支持一对多并发实时通信 | 实现细节稍微繁琐,不支持直接RPC | 网络数据交换 |
The end