正文
一、 概念QA以及前置技能
Q:什么时候会用到多进程通信?
A: 常见的多进程
app
一般是大型公司的 app组,像是腾讯系的QQ微信QQ空间,QQ邮箱
等等,有可能 在QQ邮箱
登录时,可以直接调用QQ的登录服务
,另外,腾讯阿里都有小程序,作为一个第三方开发的小程序应用,在微信客户端运行
,如果和微信放在同一个进程运行,一旦崩溃
,微信也跟着玩完,明明是小程序开发者的锅
,硬是让腾讯给背
了,不合适。而小型公司,emmmmm,连多进程开发都用的很少,就不要说通信了。但是,如果没有一颗进大厂的心,就学不到高阶技能,有些东西学了,总比一无所知要好。
Q:使用多进程有什么好处?
A: 1)进程隔离,子
app
崩溃,不会影响其他进程。2)系统运行期间,对每个进程的内存划分是有一个上限的,具体多少,视具体设备而定,利用多进程开发,可以提高程序的可运行内存限制。
3)如果系统运行期间内存吃紧,可以杀死子进程,减少系统压力。杀死进程的方式,往往比优化单个app的内存更加直接有效
Q:什么叫
RPC
?A:从客户端上通过参数传递的方式调用服务器上的一个函数并得到返回的结果,隐藏底层的通讯细节。在使用形式上像调用
本地函数
一样去调用远程函数
。
Q:我们自己定义一个
RPC
进程间通信框架,有什么实际用处?
A:定义框架的作用,都是 把脏活,累活,别人不愿意重复干的活,都放到框架里面去,让使用者用最干净的方式使用业务接口。定义一个RPC
进程间通信框架,可以把C/S两端那些恶心人的AIDL
编码都集中放到框架module
中,这是最直观的好处,另外,客户端原本还需要手动去bindService
,定义ServiceConnection
,取得Binder
,再去通信,使用RPC
框架,这些内容都可以放到框架module
中. 而C/S两端的代码,就只剩下了S端
的服务注册,C端
的RPC
接口调用,代码外观上非常简洁(可能这里文字描述不够直观,后面有图)
前置技能
要理解本文的核心代码,还是需要一些基础的,大致如下:四大组件之一
Service
使用方法, androidAIDL
通信机制, java注解,java反射,java 泛型
二、传统方式IPC通信写法
与 使用IPC框架进行RPC通信
的对比
见github : https://github.com/18598925736/MyRpcFramework , 运行 aidl_client
和 aidl_service
先展示原本效果
图中的 查找用户
,是从 服务端
读取的数据,观察一下核心代码:
这是我优化之后的 IPC
项目结构( 如果不优化,那么客户端服务端都需要编写一样的AIDL代码,还要有一个包括包名在内神马都要一模一样的JavaBean,实在是丑陋):
服务端
核心代码:
public class ServiceActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this, MyService.class));//服务端,app启动之后,自动启动服务
}
}
public class MyService extends Service {
ConcurrentMap<String, UserInfoBean> map;
@Nullable
@Override
public IBinder onBind(Intent intent) {
map = new ConcurrentHashMap<>();
for (int i = 0; i < 100; i++) {
map.put("name" + i, new UserInfoBean("name" + i, "accountNo" + i, i));
}
return new IUserInfo.Stub() {
//数据接收器 Stub
@Override
public UserInfoBean getInfo(String name) {
return map.get(name);
}
}
;
}
@Override
public void onCreate() {
super.onCreate();
Log.e("MyService", "onCreate: success");
}
}
客户端
核心代码 :
public class ClientActivity extends AppCompatActivity {
private TextView resultView;
private String TAG = "clientLog";
private int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
resultView = findViewById(R.id.resultView);
findViewById(R.id.connect).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService();
}
}
);
findViewById(R.id.disconnect).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
unbindService(connection);
resultView.setText("尝试释放");
}
catch (IllegalArgumentException e) {
resultView.setText("已经释放了");
}
}
}
);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (iUserInfo != null) {
try {
((Button) v).setText("查找name为:name" + ((i++) + 1) + "的UserInfoBean");
UserInfoBean bean = iUserInfo.getInfo("name" + i);
if (bean != null)
resultView.setText(bean.toString()); else
resultView.setText("没找到呀");
}
catch (RemoteException e) {
e.printStackTrace();
}
} else {
resultView.setText("没有连接上service");
}
}
}
);
}
//作为IPC的客户端,我们需要 建立起和Service的连接
private IUserInfo iUserInfo;
//操作句柄,可以通过它向service发送数据
private void bindService() {
if (iUserInfo == null) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(
"study.hank.com.aidl_service",
"study.hank.com.aidl_service.MyService"));
bindService(intent, connection, Context.BIND_AUTO_CREATE);
resultView.setText("尝试连接");
} else {
resultView.setText("已经连接上service" + iUserInfo);
}
}
intent, connection, Context.BIND_AUTO_CREATE);
resultView.setText("尝试连接");
} else {
resultView.setText("已经连接上service" + iUserInfo);
}
}