Binder(二)应用层使用 - AIDL

在使用跨进程通信时(IPC),需要编写大量代码,且很多代码都是模板式的,所以Android定义了AIDL(Android Interface Definition Language)文件来简化 IPC 操作。AIDL的使用流程如下:

  • 创建AIDL文件,并在其中定义业务接口
  • 编译,ADT会根据AIDL文件自动生成Java文件
  • 服务端实现AIDL生成的业务接口,并通过asBinder方法返回
  • 客户端通过binderService绑定服务
  • 客户端在收到onServiceConnected回调时,通过 asInterface 方法将回调的 IBinder 对象转化为业务接口
  • 客户端调用业务接口实现 IPC 通信

类图

在这里插入图片描述

AIDL文件

package com.whf.demolist;

interface IRemote {
    int getCount();
    void setCount(int count);
}

AIDL生成类

package com.whf.demolist.binder;

public interface IRemote extends android.os.IInterface {

    public static abstract class Stub extends android.os.Binder implements IRemote {

        /**
        * Binder的唯一标识,一般使用当前Binder的类名
        */
        private static final String DESCRIPTOR = "com.whf.demolist.IRemote";

        public Stub() {
            //将自己和DESCRIPTOR存储到Binder对象中mOwner和mDescriptor成员
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
        * 用于将服务端的Binder转换成客户端所需要的AIDL接口类型的对象,这种转换区分进程,如果客户端和服务端处同 一个进程,那么此方法返回的就是服务端的Stub本身,否则返回的是系统封装后的Stub.proxy对象
        */
        public static IRemote asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            //从Binder中查询对应DESCRIPTOR,与前面的attachInterface相对应
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof IRemote))) {
                return ((IRemote) iin);
            }
            return new Stub.Proxy(obj);
        }

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

        /**
        * 该方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理
        * @param code 服务端通过改参数可以确定客户端所请求的目标方法是什么
        * @param data 目标方法所需要的参数(如果目标方法有参数的话)
        * @param reply 方法执行完成后,其返回值写入到该参数中
        * @return 返回false代表客户端请求失败
        */
        @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_getCount: {
                    //校验是否合法
                    data.enforceInterface(DESCRIPTOR);
                    int _result = this.getCount();
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                case TRANSACTION_setCount: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    this.setCount(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
        
        private static class Proxy implements IRemote {
            //BinderProxy对象,Binder的代理,用于多进程通信时向Binder写入数据
            private android.os.IBinder mRemote;

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

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

            public String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public int getCount() throws android.os.RemoteException {
                //创建所需要的输入型Parcel对象(从parcel池中获取,如果池中没有了就新建)
                android.os.Parcel _data = android.os.Parcel.obtain();
                //创建所需要的输出型Parcel对象
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    //将该方法的参数写入_data中 ( 该方法无参数,所以不用写,详见setCount()方法 )
                    _data.writeInterfaceToken(DESCRIPTOR);
                    //发起RPC(远程过程调用)请求,实际调用的是onTransact方法,并且当前线程挂起,直至RPC过程返回,当前线程继续执行
                    mRemote.transact(Stub.TRANSACTION_getCount, _data, _reply, 0);
                    //从_reply中取出RPC过程的返回结果
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void setCount(int count) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    //将该方法的参数写入_data中
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(count);
                    mRemote.transact(Stub.TRANSACTION_setCount, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        //方法的唯一标识
        static final int TRANSACTION_getCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_setCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public int getCount() throws android.os.RemoteException;
    public void setCount(int count) throws android.os.RemoteException;
}

Service端实现

public class AidlService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return remoteStub ;
    }
    
    //服务端实现业务接口
	private IRemote.Stub remoteStub = new IRemote.Stub() {
    	@Override
    	public int getCount() throws RemoteException {
        	return count;
    	}
    	@Override
    	public void setCount(int count) throws RemoteException{
        	RemoteService.this.count = count;
    	}
	};
}

Clinet端使用

//ClientActivity中
IRemote remoteService;
bindService(bindServiceIntent, connection, Context.BIND_AUTO_CREATE);

//ServiceConnection
public ServiceConnection connection = new ServiceConnection() {
	@Override
	public void onServiceConnected(ComponentName name, IBinder service) {
		//获取 Service 端引用
    	ClientActivity.this.remoteService = IRemote.Stub.asInterface(service);
    	//设置死亡监听
    	try {
        	service.linkToDeath(deathRecipient,0);
    	} catch (RemoteException e) {
        	e.printStackTrace();
    	}
	}
	
	@Override
	public void onServiceDisconnected(ComponentName name) {
		ClientActivity.this.remoteService = null;
	}
};

/**
 * 死亡监听,当Binder连接断裂(称之为Binder死亡),会导致远程调用失败,更为关键的是我们并不知道Binder已经
 * 断开连接,那么客户端的功能就会一直受影响,所以可以通过设置Binder的死亡监听,当Binder死亡时就会收到通知
 * 另外也可以同过Binder的 isBinderAlive 方法去主动判断Binder是否死亡
 */
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
    @Override
    public void binderDied() {
        if (remoteService==null){
            return;
        }
        remoteService.asBinder().unlinkToDeath(deathRecipient,0);
        remoteService = null;
        //重新绑定远程服务
        bindRemoteService();
    }
};

定向Tag

所有的非基本参数都需要一个定向Tag来指出数据流通的方式,不管是in , out , 还是 inout ,基本参数的定向Tag默认是并且只能是 in。

  • in :数据只能由客户端流向服务端
  • out:数据只能由服务端流向客户端
  • inout:数据可在服务端与客户端之间双向流通
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值