安卓的跨进程通信IPC
本文源码地址: https://github.com/stdroom/BinderDemo
Binder简介:
安卓系统基于Linux,但Binder是安卓独有的跨进程通信方式
- 从系统层来讲Binder也是一个虚拟设备,驱动在/dev/binder中;
- 从framework层来讲,binder是ServiceManager连接各种Manager(ActivityManager,WindowManger...)和ManagerService的桥梁;
- 从应用层来讲,Binder是客户端和服务端通信的桥梁,客户端可以通过服务端返回的Binder来调用服务端的各种实现。
2. Aidl实现梳理
通过aidl来了解Binder机制
- 为什么要设计AIDL语言?
- AIDL的语法是什么?
- 如何使用AIDL语言完成跨进程通信?
- AIDL与Binder的区别是什么
- 绑定服务的几种方式 BIND_AUTO_CREATE...
2.1 定义实体类 和 远程调用接口
Book.java类 实现Parcelable接口
public class Book implements Parcelable{
private long bookId;
private String bookName;
....
}
Book.aidl
package com.lxbinder.demo;
parcelable Book;
IBookInterface.aidl类
必须导入Book类 否则不能识别,Book类必须实现序列化接口
package com.lxbinder.demo;
import com.lxbinder.demo.Book;
interface IBookInterface {
void addBook(long bookId,String bookName);
List getBook();
}
2.2 实现Service端实现
public class BookService extends Service{
private ArrayList books = new ArrayList<>();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private IBookInterface.Stub mBinder = new IBookInterface.Stub() {
@Override
public void addBook(long bookId, String bookName) throws RemoteException {
books.add(new Book(bookId,bookName));
}
@Override
public List getBook() throws RemoteException {
return books;
}
};
}
2.3 实现客户端调用
客户端Activity实现ServiceConnection接口
需要注意的是:远程调用会挂起当前线程,直到服务端返回数据时唤醒当前进程,所以要当成耗时任务对待,本示例忽略
public MainActivity extends AppCompatActivity implements View.OnClickListener,ServiceConnection{
// asInterface :如果service为本地进程,直接返回服务端的Stub对象本身,否则返回的是Stub.Proxy代理对象
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mBinder = IBookInterface.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
unbindService(this);
mBinder = null;
}
// 绑定服务
private void startBind(){
Intent intent = new Intent(this,BookService.class);
this.bindService(intent,this, Context.BIND_AUTO_CREATE);
}
// 从服务端获取 图书列表 并在本地客户端打印
private void printbooks(){
if(mBinder!=null){
try{
List books = mBinder.getBook();
StringBuilder sb = new StringBuilder();
for(int i = 0 ;i< books.size();i++){
sb.append("索引:"+i+" bookId: "+books.get(i).getBookId()+" 书名 "+books.get(i).getBookName()+"\n");
}
bookShowTv.setText(sb.toString());
}catch (Exception e){
e.printStackTrace();
}
}
}
private void addBook(){
if(mBinder!=null){
try{
mBinder.addBook(bookIdIndex++,"图书"+bookIdIndex);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
2.4 接口aidl具体实现类的关键方法解析
android studio 为我们自动生成IBookInterface.aidl的实现类
分析如下
静态方法asInterface,区分是否当前进程,分别返回具体的Stub对象还是Stub.Proxy对象
public static com.lxbinder.demo.IBookInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.lxbinder.demo.IBookInterface))) {
return ((com.lxbinder.demo.IBookInterface)iin);
}
return new com.lxbinder.demo.IBookInterface.Stub.Proxy(obj);
}
3. 手动模仿AIDL实现
关键类实现
- IUserAIDL 客户端服务端通信 接口定义
- UserStub (Binder)
- UserProxy (接口实现)
1.IUSerAIDL
interface IUserAIDL extends android.os.IInterface{
final String DESCRIPTOR = "com.lxbinder.demo.IUserAIDL";
int TRANSACTION_addUser = 0;
int TRANSACTION_getUserList = 1;
void addUser(long userId,String userName) throws RemoteException;
List getUserList() throws RemoteException;
}
- UserProxy
public class UserProxy implements IUserAIDL {
private IBinder mRemote;
UserProxy(IBinder remote)
{
mRemote = remote;
}
@Override
public IBinder asBinder(){
return null;
}
@Override
public void addUser(long userId,String userName) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
data.writeLong(userId);
data.writeString(userName);
mRemote.transact(IUserAIDL.TRANSACTION_addUser, data, reply, 0);
reply.readException();
}
finally {
reply.recycle();
data.recycle();
}
}
@Override
public List getUserList() throws RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getUserList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(User.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
UserStub
abstract class UserStub extends Binder implements IUserAIDL {
public UserStub(){
this.attachInterface(this,DESCRIPTOR);
}
@Override
public IBinder asBinder(){
return this;
}
public static IUserAIDL asInterface(IBinder obj){
if(obj == null){
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if(iin!=null && (iin instanceof IUserAIDL)){
return (IUserAIDL)iin;
}
return new UserProxy(obj);
}
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case TRANSACTION_addUser:
data.enforceInterface(DESCRIPTOR);
long userId = data.readLong();
String name = data.readString();
reply.writeNoException();
addUser(userId,name);
return true;
case TRANSACTION_getUserList:
data.enforceInterface(DESCRIPTOR);
java.util.List _result = this.getUserList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
default:
break;
}
return super.onTransact(code, data, reply, flags);
}
}