android Binder 实现—— AIDL demo

1 篇文章 0 订阅
1 篇文章 0 订阅

服务间进程通信大部分使用AIDL,其其次原理是Binder ,先写一个Demo, 可以参考 这里 。

一 、AIDL 使用教程

1.1 创建要操作的实体类,实现 Parcelable 接口,以便序列化/反序列化 (Serizable没试过,不知道行不行)

public class Book implements Parcelable {

    private int bookId;
    private String bookName;

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

    public int getBookId() {
        return bookId;
    }

    public void setBookId(int bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookId=" + bookId +
                ", bookName='" + bookName + '\'' +
                '}';
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);
    }

    public static final Creator<Book> CREATOR = new Creator<Book>(){
        @Override
        public Book createFromParcel(Parcel source) {
            return new Book(source);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    private Book(Parcel in){
        bookId = in.readInt();
        bookName = in.readString();
    }
}

1.2 新建 aidl 文件夹,在其中创建接口 aidl 文件以及实体类的映射 aidl 文件

注意,利用as IDE创建AIDL文件,鼠标放在main 文件夹上,然后右键,再new—— AIDL 文件即可,这样就会得到上图的文件结构,注意这里aidl文件会区别java文件,同时后面的文件夹名称一致(不然会出错),接着创建实体类对应的映射的AIDL文件,如下:

可以看到这里什么都没有写,只有一个定义 

parcelable Book;

先不管为啥,就这样写吧先。接着在写接口文件:

这里写了两个方法,一个是获取列表,一个是添加书的方法,basicTypes方法是系统生成的,可以去掉; 

一般来说, AIDL 文件支持以下类型

  • Java 编程语言中的所有原语类型(如 int、long、char、boolean 等等)
  • String
  • List  只支持ArrayList ,其中所有元素都必须是AIDL支持的类型
  • Map 只支持HashMap,其中所有元素都必须是AIDL支持的类型
  • 实现 Parceable 的自定义类型


注意事项

  • 在 aidl 文件中,除了 Java 编程语言中的所有原语类型、String、CharSequence、List、Map,其他在 AIDL 文件中用到的类,你必须使用 import 语句导入,否则会报错。比如上面的 Person,需要导入它的全路径
  • 当你使用实现Parceable 的自定义类型的时候,当其作为参数的时候,你必须为其制定是输入或者是输出参数。

in 表示输入参数,即服务端可以修改该类型
out 表示输出参数,即客户端可以修改该类型
inout  表示客户端和服务端都可以修改该类型

 接着就是reBuild ,重新编译一下工程,这样工程就会在build——generated——source——aidl 目录下生成模板代码(一定要把上面的所有步骤做完了才能重新编译,否则会出错)。

1.3 编写服务端代码

这里是绑定服务,和启动服务不一样,要实现onBind()方法,代码如下:

public class MyService extends Service {


    private final String TAG = this.getClass().getSimpleName();

    private ArrayList<Book> mBooks;

    private IBinder mIBinder = new IBookManager.Stub() {
        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBooks;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            mBooks.add(book);
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        mBooks = new ArrayList<>();
        Log.d(TAG, "onBind: ");
        return mIBinder;
    }
}

别忘记在 Manifest 文件中声明:

<service
    android:name=".MyService"
    android:process=":aidl"/>

1.4 客户端代码

逻辑:在客户端调用aidl调用服务端的相关方法,并从服务端获取数据,客户端和服务端不在同一进程,但实现了通信。

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private IBookManager mIBookManager;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //连接后拿到 Binder,转换成 AIDL,在不同进程会返回个代理
            mIBookManager = IBookManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mIBookManager = null;
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);



    }

    public void clickView(View view){
        //startActivity(new Intent(this, AnotherProcessActivity.class));
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

    }

    public void ToIndenpentProcess(View view){
        //startActivity(new Intent(this, AnotherProcessIndepentActivity.class));
        // 跨进程通信 在service进程中添加数据,在Activity进程获取数据 中间通过aidl实现
        Random random = new Random();
        Book book = new Book(random.nextInt(10), "bookName");
        try {
            mIBookManager.addBook(book);
            List<Book> personList = mIBookManager.getBookList();
            for (int i = 0; i < personList.size(); i++) {
                Log.d(TAG, "ToIndenpentProcess: " + personList.get(i));
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }

这样就完成了整个AIDL的使用了,大致有三步骤:

  • 创建AIDL接口文件定义相关方法;
  • 创建服务代码,实现相关逻辑(这里以service为例,实现onBind方法)
  • 创建客户端,实现相关逻辑;

二、IBookManger 的类代码

分析as把AIDL文件转换的代码贴出来:

public interface IBookManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.a41082.multiprocess.IBookManager {
        private static final java.lang.String DESCRIPTOR = "com.example.a41082.multiprocess.IBookManager";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.example.a41082.multiprocess.IBookManager interface,
         * generating a proxy if needed.
         */
        public static com.example.a41082.multiprocess.IBookManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.a41082.multiprocess.IBookManager))) {
                return ((com.example.a41082.multiprocess.IBookManager) iin);
            }
            return new com.example.a41082.multiprocess.IBookManager.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_getBookList: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<com.example.a41082.multiprocess.Book> _result = this.getBookList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook: {
                    data.enforceInterface(DESCRIPTOR);
                    com.example.a41082.multiprocess.Book _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.example.a41082.multiprocess.Book.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.example.a41082.multiprocess.IBookManager {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            /**
             * Demonstrates some basic types that you can use as parameters
             * and return values in AIDL.
             */
            @Override
            public java.util.List<com.example.a41082.multiprocess.Book> getBookList() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.example.a41082.multiprocess.Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.example.a41082.multiprocess.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void addBook(com.example.a41082.multiprocess.Book book) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((book != null)) {
                        _data.writeInt(1);
                        book.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public java.util.List<com.example.a41082.multiprocess.Book> getBookList() throws android.os.RemoteException;

    public void addBook(com.example.a41082.multiprocess.Book book) throws android.os.RemoteException;
}

这里主要是 内部类 Stub ,这是一个Binder, 然后内部有onTransact()方法,主要是 用这个方法和服务端进行交互,然后会通过reply 进行返回数据给Binder,binder再给客户端。

Binder原理参考 这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值