Android IPC简介
IPC 全称为Inter-Process Communication,译为“跨进程通信”含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程;在这里要着重提一下,进程(Process)和线程(Thread)是完全不一样的概念,两者不能混淆;在操作系统的概念里,进程是CPU的调度单元,而线程是CPU的最小调度单位,一个进程包含一个或一组线程,两者为包含关系
Android 进程间 IPC 通信方式
Android进程间通信(IPC:Inter-Process Communication)的几种主要方式如下:
● 使用Bundle ----> 用于android四大组件间的进程间通信
android的四大组件都可使用Bundle传递数据 所以如果要实现四大组件间的进程间通信 完全可以使用Bundle来实现 简单方便
● 使用文件共享 ---->用于单线程读写
这种方式在单线程读写的时候比较好用 如果有多个线程并发读写的话需要限制线程的同步读写
另外 SharePreference是个特例 它底层基于xml实现 但是系统对它的读写会基于缓存,也就是说再多进程模式下就变得不那么可靠了,有很大几率丢失数据
● 使用Messenger ---->用于可存放在message中的数据的传递
使用这个方式可以在不同进程间传递message对象 这是一种轻量级的IPC方案 当传递的对象可以放入message中时 可以考虑用这种方式
但是msg.object最好不要放;因为不一定可以序列化
Android IPC 调用
Android是基于linux内核的;所以linux支持的 IPC ,Android 都用到了;比如命名管道,共享内存;除此外,Android 还使用了一套自己独特的 IPC 方式 Binder .;主要用于2个进程间的远程调用,但是这里就牵扯远程调用如何传递参数,如何回传结果;这需要调用者对数据进行打包和解包,是一个繁琐的过程
为此,Android 引入了 AIDL (Android interface description launguage). 开发人员定义好 AIDL ,Android 会根据 AIDL 的描述生产 stub 代码,帮助调用者对数据打包,解包;开发人员所要做的事是继承stub代码,实现stub代码中的函数;这些函数是你在aidl中定义的
AIDL的实现
在Android中有多种实现IPC的方式,各有各的优缺点,我们拿其中一种最常用方式来更深入的了解一下Android中IPC的实现方式,从而彻底理解其工作方式
我们用一个最简单的场景:服务端提供计算的方法计算两个数之和并返回;客户端调用服务端的方法得出结果并显示
首先是服务端:
我们首先创建一个AIDL文件,其实就是定义我们的方法接口
// IMyAdd.aidlpackage
test.jiao.com.aidl;
interface IMyAdd {
int add(int first,int second);
}
其中定义了一个两个数相加的方法接下来我们创建一个Service
package test.jiao.com.aidl;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
/**
* date :2016/12/26
* author :SuperJiao
* Description
*/
public class MyAddService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private Binder mBinder = new IMyAdd.Stub() {
@Override
public int add(int first, int second) throws RemoteException {
return first + second;
}
};
}
我们在Service中实现了我们定义的AIDL接口,并且服务端在绑定接口的时候将服务端的IBinder对象返回给客户端;客户端拿到服务端的IBinder对象就可以调用服务端的方法了
客户端实现如下:
和服务端定义一个一模一样的aidl文件(包名、方法名,参数必须一致)
// IMyAdd.aidlpackage
test.jiao.com.aidl;
interface IMyAdd {
int add(int first,int second);
}
绑定服务端的服务
package test.jiao.com;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.Toast;
import test.jiao.com.aidl.IMyAdd;
public class MainActivity extends Activity {
private Button bt_aidl_add;
private IMyAdd mIMyAdd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start();
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(MainActivity.this, "绑定服务成功", Toast.LENGTH_SHORT).show();
mIMyAdd = IMyAdd.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private void start() {
bindService();//绑定服务
bt_aidl_add = (Button) findViewById(R.id.bt_aidl_add);
bt_aidl_add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mIMyAdd != null) {
try {
int result = mIMyAdd.add(5, 5);
Toast.makeText(MainActivity.this, result + "", Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "计算失败", Toast.LENGTH_SHORT).show();
}
}
});
}
//绑定服务
private void bindService() {
Intent intent = new Intent();
intent.setAction("com.jiao.myaidl.action.MYADD_SERVICE");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(serviceConnection);//解绑服务
super.onDestroy();
}
}
接下来我们来分析一下整个AIDL的执行过程:
● 首先服务端的MyAddService在自己的进程中向Binder驱动申请创建了一个MyAddService的Binder实体;Binder驱动为MyAddService创建了位于内核中的Binder实体节点以及Binder的引用,并将名字和新建的引用打包传递给SM(实体没有传给SM),通知SM注册一个MyAddService
● SM收到数据包后,从中取出MyAddService名字和引用,填入一张查找表中。在启动服务的时候,SM就会从这张查找表中查找相应的服务
● 客户端Client申请访问MyAddService,SM就会从请求数据包中获得MyAddService的名字,在查找表中找到该名字对应的条目,取出Binder的引用打包回复给client;之 后,Client就可以利用MyAddService的引用使用MyAddService的服务了
如果需要文章中使用的源码的同学,可以顺手给我点赞评论支持一下
资料获取方式
现在点击:免费获取更多Android进阶资料,学习笔记,面试真题
Android架构师之路还很漫长,与君共勉
PS:有问题欢迎指正,欢迎大家点赞评论,可以在评论区留下你的建议和感受
网友评论