安卓IPC通信:Binder机制总结及 AIDL模仿实现

安卓的跨进程通信IPC

本文源码地址: https://github.com/stdroom/BinderDemo

Binder简介:

安卓系统基于Linux,但Binder是安卓独有的跨进程通信方式

  1. 从系统层来讲Binder也是一个虚拟设备,驱动在/dev/binder中;
  2. 从framework层来讲,binder是ServiceManager连接各种Manager(ActivityManager,WindowManger...)和ManagerService的桥梁;
  3. 从应用层来讲,Binder是客户端和服务端通信的桥梁,客户端可以通过服务端返回的Binder来调用服务端的各种实现。
image.png

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;
}

  1. 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);
    }

}

你可能感兴趣的:(安卓IPC通信:Binder机制总结及 AIDL模仿实现)