aidl学习记录2

前言

首先,这篇文章主要是基于上一篇文章aidl的学习记录来继续学习的,所以没看过上一篇文章的可以先看看。

AidlBookManager文件

上一篇文章通过aidl在 build/generated/source/aidl/你的 flavor/ 下生成一个 Java 文件AidlBookManager.java。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\workspace\\aidlTestClient\\app\\src\\main\\aidl\\kanghb\\com\\aidltest\\AidlBookManager.aidl
 */
package kanghb.com.aidltest;

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

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

        /**
         * Cast an IBinder object into an kanghb.com.aidltest.AidlBookManager interface,
         * generating a proxy if needed.
         */
        public static kanghb.com.aidltest.AidlBookManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof kanghb.com.aidltest.AidlBookManager))) {
                return ((kanghb.com.aidltest.AidlBookManager) iin);
            }
            return new kanghb.com.aidltest.AidlBookManager.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_getBooks: {
                    data.enforceInterface(DESCRIPTOR);
                    java.util.List<kanghb.com.aidltest.Book> _result = this.getBooks();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook: {
                    data.enforceInterface(DESCRIPTOR);
                    kanghb.com.aidltest.Book _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = kanghb.com.aidltest.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 kanghb.com.aidltest.AidlBookManager {
            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<kanghb.com.aidltest.Book> getBooks() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<kanghb.com.aidltest.Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(kanghb.com.aidltest.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
            //传参时除了Java基本类型以及String,CharSequence之外的类型
            //都需要在前面加上定向tag,具体加什么量需而定

            @Override
            public void addBook(kanghb.com.aidltest.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_getBooks = (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<kanghb.com.aidltest.Book> getBooks() throws android.os.RemoteException;
    //传参时除了Java基本类型以及String,CharSequence之外的类型
    //都需要在前面加上定向tag,具体加什么量需而定

    public void addBook(kanghb.com.aidltest.Book book) throws android.os.RemoteException;
}

客户端服务端根据这个系统生成的Binder来进行进程间通讯。。

AidlBookManager文件结构

0.DESCRIPTOR,Binder的唯一标识,当前Binder的类名表示

        private static final java.lang.String DESCRIPTOR = "kanghb.com.aidltest.AidlBookManager";

1.AidlBookManager继承了android.os.IInterface这个接口,自己也是个接口。

2.声明了两个在AidlBookManager.aidl中定义的方法

 public java.util.List<kanghb.com.aidltest.Book> getBooks() throws android.os.RemoteException;
 public void addBook(kanghb.com.aidltest.Book book) throws android.os.RemoteException;

3.声明两个整形id标识上面两个方法,用于在transact过程中客户端所请求的到底是哪个方法

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

4.声明一个内部类Stub继承Binder类,Stub内部声明一个代理类Proxy,接口的核心实现就是由Stub和Stub.Proxy组成。

AidlBookManager重要方法

Stub相关

  1. asInterface(android.os.IBinder obj)

      public static kanghb.com.aidltest.AidlBookManager asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof kanghb.com.aidltest.AidlBookManager))) {
                    return ((kanghb.com.aidltest.AidlBookManager) iin);
                }
                return new kanghb.com.aidltest.AidlBookManager.Stub.Proxy(obj);
            }
    

    用于将服务端的Biner对象转化为客户端需要的aidl接口类型的对象。如果客户端服务端属于同一个进程,返回Stub对象本身,否则返回Stub.Proxy对象。

  2. asBinder

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

    用于返回当前Binder对象

  3. onTransact

      @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_getBooks: {
                        data.enforceInterface(DESCRIPTOR);
                        java.util.List<kanghb.com.aidltest.Book> _result = this.getBooks();
                        reply.writeNoException();
                        reply.writeTypedList(_result);
                        return true;
                    }
                    case TRANSACTION_addBook: {
                        data.enforceInterface(DESCRIPTOR);
                        kanghb.com.aidltest.Book _arg0;
                        if ((0 != data.readInt())) {
                            _arg0 = kanghb.com.aidltest.Book.CREATOR.createFromParcel(data);
                        } else {
                            _arg0 = null;
                        }
                        this.addBook(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    

    运行在服务端的Binder线程池中,服务端通过参数code判断请求的目标方法,从data中取出方法所需要的参数(如果目标方法有参数的话),然后执行目标方法,执行完毕后向reply中写入返回值(如果目标方法有返回值的话)。如果onTransact返回false,则客户端请求失败。

Stub.Proxy相关

1.getBooks

 @Override
            public java.util.List<kanghb.com.aidltest.Book> getBooks() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<kanghb.com.aidltest.Book> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArrayList(kanghb.com.aidltest.Book.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

运行在客户端,客户端调用此方法时,首先创建Parcel对象:输入型_data和输出型_reply,返回值对向List,把参数写入_data中,调用transact方法发起远程过程调用请求,线程挂起等待,服务端的onTransact方法被调用,一直到RPC结束后,继续执行当前线程,从_reply中取出返回的结果,最后返回_result数据。

2.addBook(kanghb.com.aidltest.Book book)

 @Override
            public void addBook(kanghb.com.aidltest.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();
                }
            }

和getBooks执行逻辑一样。

注意点

客户端发起远程请求时,由于当前线程会被挂起至服务器端进程返回数据,所以如果一个远程方法是耗时的,那么不能再UI线程中发起远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以不管Binder是否耗时,都应该才用同步方法实现,因为它已经运行在一个线程中了。

Binder 死亡处理

在进程间通信过程中,很可能出现一个进程死亡的情况。如果这时活着的一方不知道另一方已经死了就会出现问题。那我们如何在 A 进程中获取 B 进程的存活状态呢?
Android 肯定给我们提供了解决方式,那就是 Binder 的 linkToDeath 和 unlinkToDeath 方法, linkToDeath 方法需要传入一个 DeathRecipient 对象, DeathRecipient 类里面有个 binderDied 方法,当 binder 对象的所在进程死亡, binderDied 方法就会被执行,我们就可以在 binderDied 方法里面做一些异常处理,释放资源等操作了。

声明一个DeathRecipient对象,实现binderDied()方法,移除之前绑定的binder代理并重新绑定远程服务。

   private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            Log.e(getLocalClassName(), "服务死亡了,要开始重连了");
            if(aidlBookManager == null)
                return;
            aidlBookManager.asBinder().unlinkToDeath(mDeathRecipient,0);
            aidlBookManager = null;

            //重新绑定远程services
            attemptToBindService();
        }
    };

在客户端绑定远程服务成功后,给binder设置死亡代理

 @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(getLocalClassName(), "service connected");
            aidlBookManager = AidlBookManager.Stub.asInterface(service);
            try {
                aidlBookManager.asBinder().linkToDeath(mDeathRecipient,0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            。。。。省略
        }

这样就给Binder设置了死亡代理,当Binder死亡的时候我们就可以收到通知了。当客户点app连接到服务端app后,杀死服务店app然后看到如下效果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值