美文网首页
安卓IPC通信:Binder机制总结及 AIDL模仿实现

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

作者: ammike | 来源:发表于2017-11-15 18:44 被阅读0次

    安卓的跨进程通信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<Book> getBook();
    }
    
    

    2.2 实现Service端实现

    public class BookService extends Service{
        private ArrayList<Book> 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<Book> 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<Book> 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<User> 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<User> getUserList() throws RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            java.util.List<User> _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<User> _result = this.getUserList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                default:
                    break;
            }
            return super.onTransact(code, data, reply, flags);
        }
    
    }
    

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/ewuhvxtx.html