天天看点

手写一个AIDL一、客户端二、服务端

客户端demo:https://github.com/hewind/AidlClientTest

服务端demo:https://github.com/hewind/AidlServerTest

实现功能:增加人员、删除人员、获取人员信息;

一、客户端

1、创建PersonBean实体类

public class PersonBean implements Parcelable {

    private String name;

    public PersonBean(String name) {
        this.name = name;
    }
    public String getName() {
        return name == null ? "" : name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "PersonBean{" + "name='" + name + '\'' + '}';
    }


    protected PersonBean(Parcel in) {
        name = in.readString();
    }
    public static final Creator<PersonBean> CREATOR = new Creator<PersonBean>() {
        @Override
        public PersonBean createFromParcel(Parcel in) {
            return new PersonBean(in);
        }
        @Override
        public PersonBean[] newArray(int size) {
            return new PersonBean[size];
        }
    };
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(name);
    }

    //删除使用
    @Override
    public boolean equals(@Nullable Object obj) {
        if (this == obj){//自反性
            return true;
        }
        if (!(obj instanceof PersonBean)){//instanceof比较判断是否是同一类或者子父类关系
            return false;
        }
        if (this.name.equals(((PersonBean) obj).getName())){//判断是同一类或者子父类关系,再将Object类型强转为Students
            return true;
        }
        return false;
    }
    @Override
    public int hashCode() {
        return name.hashCode();
    }
}
           

PersonBean实现Parcelable接口,目的为了跨进程传输,重写equals和hashCode方法目的为了使用删除;

2、创建PersonManagerInterface接口

public interface PersonManagerInterface extends IInterface {

    //添加人数
    void addPerson(PersonBean personBean) throws RemoteException;

    //删除人数
    void deletePerson(PersonBean personBean) throws RemoteException;

    //获取人数
    List<PersonBean> getPerson() throws RemoteException;
}
           

创建PersonManagerInterface接口,并实现IInterface接口,只有实现IInterface接口,才具备跨进程传输的基础能力,另外如果我们使用Android Studio自带的创建AIDL生成的aidl文件,也是继承了该IInterface接口,这里自己手动创建并继承效果是一样的。

3、创建Proxy代理类

public class Proxy implements PersonManagerInterface {

    //远程binder对象
    private IBinder iBinder;
    //Binder ID
    private static final String DESCRIPTOR = "com.example.aidlservertest.Proxy.PersonManagerInterface";

    public Proxy(IBinder iBinder) {
        this.iBinder = iBinder;
    }

    //增加人数实现
    @Override
    public void addPerson(PersonBean personBean) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel replay = Parcel.obtain();
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            if (personBean != null){
                data.writeInt(1);
                personBean.writeToParcel(data,0);
            }else {
                data.writeInt(0);
            }
            iBinder.transact(Stub.TRANSAVTION_addperson,data,replay,0);
            replay.readException();
        }finally {
            replay.recycle();
            data.recycle();
        }
    }
    //删除人数实现
    @Override
    public void deletePerson(PersonBean personBean) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel replay = Parcel.obtain();
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            if (personBean != null){
                data.writeInt(1);
                personBean.writeToParcel(data,0);
            }else {
                data.writeInt(0);
            }
            iBinder.transact(Stub.TRANSAVTION_deleteperson,data,replay,0);
            replay.readException();
        }finally {
            replay.recycle();
            data.recycle();
        }
    }
    //查询人数实现
    @Override
    public List<PersonBean> getPerson() throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel replay = Parcel.obtain();
        List<PersonBean> result;
        try {
            //写入一个校验
            data.writeInterfaceToken(DESCRIPTOR);
            //客户端调用到这个方法,走到iBinder.transact,此时会进入系统层处理,处理结果通过调用Stub的transact方法返回,系统层处理过程会阻塞在这行代码,直到处理完成,
            iBinder.transact(Stub.TRANSAVTION_getpersons,data,replay,0);
            //上面一行代码在系统处理成功后,返回结果,由于Stub的transact方法写入了一个【reply.writeNoException()】,这里reply进行读取异常
            replay.readException();
            //这里是Stub的transact方法处理返回的结果
            result = replay.createTypedArrayList(PersonBean.CREATOR);
        }finally {
            replay.recycle();
            data.recycle();
        }
        return result;
    }

    /**
     * 方法说明:返回当前获取到的服务端的IBander
     * 日期:2020-09-09 10:31
     */
    @Override
    public IBinder asBinder() {
        return iBinder;
    }

}
           
  1. Proxy在AIDL通信中承担着发送信息的角色;
  2. Proxy实现了PersonManagerInterface接口,同时实现asBinder方法,该方法返回一个iBinder对象,该iBinder对象由Stub类实例化Proxy并传入iBinder对象;
  3. DESCRIPTOR为BinderID,一般由包名+PersonManagerInterface组成;
  4. 获取人数信息getPerson方法中data为要传送的数据,reply为接收返回的数据;data.writeInterfaceToken(DESCRIPTOR)方法为写入binderID作为校验,服务端的Stub方法收到后也会进行一个校验;接下来开始调用iBinder的transact方法,该方法会直接进入系统层处理,最终会调用到Binder驱动,然后通过Binder调用服务端的Stub的ontTransact方法建立起一个完整的沟通机制;另外在调用该方法时系统会阻塞线程进入等待,直到返回处理结果;

4、创建Stub类

public abstract class Stub extends Binder implements PersonManagerInterface  {

    //Binder ID
    private static final String DESCRIPTOR = "com.example.aidlservertest.Proxy.PersonManagerInterface";

    public Stub() {
        //attachInterface方法:向BinderService注册Binder服务。只有注册了binder,客户端才能查询到有这个binder对象,并使用它
        this.attachInterface(this,DESCRIPTOR);
    }

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

    //将服务端的Binder对象准换成客户端所需要的AIDL接口对象,
    public static PersonManagerInterface asInterface(IBinder iBinder){
        if ((iBinder==null)) {
            return null;
        }
        //查询当前进程,如果客户端和服务端位于同一进程,那么此方法返回的就是当前进程的Stub对象本身,否则返回服务端进程的Stub.proxy对象(服务端也有该Stub类)
        IInterface iin = iBinder.queryLocalInterface(DESCRIPTOR);
        if ((iin != null) && (iin instanceof PersonManagerInterface)) {
            return (PersonManagerInterface)iin;
        }
        //返回服务端的Stub.proxy对象
        return new Proxy(iBinder);
    }

    //这个方法运行在服务端中的Binder线程池当中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。
    @Override
    protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
        switch (code){
            case INTERFACE_TRANSACTION:
                reply.writeString(DESCRIPTOR);
                return true;
            case TRANSAVTION_addperson://增加人数
                //返回一个校验
                data.enforceInterface(DESCRIPTOR);
                PersonBean personBean = null;
                if (data.readInt() != 0){
                    //读取PersonBean
                    personBean = PersonBean.CREATOR.createFromParcel(data);
                }
                //接口方法回调出去,这里最终会走到服务端的Service类的IBinder回调中
                this.addPerson(personBean);
                //返回一个无异常
                reply.writeNoException();
                return true;
            case TRANSAVTION_deleteperson://删除人数
                data.enforceInterface(DESCRIPTOR);
                PersonBean personBean2 = null;
                if (data.readInt() != 0){
                    personBean2 = PersonBean.CREATOR.createFromParcel(data);
                }
                this.deletePerson(personBean2);
                reply.writeNoException();
                return true;
            case TRANSAVTION_getpersons://获取人数
                data.enforceInterface(DESCRIPTOR);
                List<PersonBean> result = this.getPerson();
                reply.writeNoException();
                reply.writeTypedList(result);
                return true;
        }
        return super.onTransact(code, data, reply, flags);
    }

    //使用int型代替字符串传递来标识调用的是哪一个方法,属于性能优化
    public static final int TRANSAVTION_getpersons = IBinder.FIRST_CALL_TRANSACTION;
    public static final int TRANSAVTION_addperson = IBinder.FIRST_CALL_TRANSACTION + 1;
    public static final int TRANSAVTION_deleteperson = IBinder.FIRST_CALL_TRANSACTION + 2;
}
           
  1. Stub在AIDL通信中承担着接收信息的角色;
  2. Stub类继承了Binder,同时实现了PersonManagerInterface接口;
  3. 无参构造器中,Stub类调用了一个attachInterface方法,传入了当前对象以及BinderID,该方法是向BinderService注册Binder服务,只有注册了Binder,客户端才能查询到这个Binder对象并使用它;
  4. asBinder方法返回的是当前对象,实际上跟Proxy中asBinder方法返回的是同一个Binder对象;
  5. asInterface方法是将服务端的BInder对象转换成客户端所需要的AIDL接口对象,iBinder.queryLocalInterface(DESCRIPTOR)方法会先查询一下本地进程的DESCRIPTOR是否为null,不为null的话就直接返回PersonManagerInterface接口对象;否则就实例化Proxy,并传入iBinder对象;
  6. onTransact方法即为BInder驱动处理后返回给服务端的出口,这个方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,请求经过BInder处理,再交给该方法;
  7. 其中code参数为方法代理名称,使用数字来代替客户端想要调用的某个方法名,如果有多个方法名,会在IBinder.FIRST_CALL_TRANSACTION默认上进行加1,以此类推;

5、客户端绑定服务

public class MainActivity extends AppCompatActivity {

    private Button button,button2,button3;
    private TextView textView;

    private PersonManagerInterface personManagerInterface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        prePareAidl();
        
        textView = findViewById(R.id.textview);
        button = findViewById(R.id.button);
        button2 = findViewById(R.id.button2);
        button3 = findViewById(R.id.button3);
        //添加人员
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PersonBean personBean = new PersonBean();
                personBean.setName("张三");
                try {
                    personManagerInterface.addPerson(personBean);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                getPerson();
            }
        });
        //删除人员
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PersonBean personBean = new PersonBean();
                personBean.setName("张三");
                try {
                    personManagerInterface.deletePerson(personBean);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                getPerson();
            }
        });
        //获取人员
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getPerson();
            }
        });
    }

    /**
     * 方法说明:获取Person人数
     * 日期:2020-09-11 16:36
     */
    private void getPerson() {
        try {
            List<PersonBean> list = personManagerInterface.getPerson();
            String str = "";
            for (PersonBean p:list){
                str += p.getName()+", ";
            }
            textView.setText(str);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /**
     * 方法说明:通过绑定远程service,初始化远程iBinder实例
     * 日期:2020-09-09 17:14
     */
    private void prePareAidl() {
        Intent intent = new Intent();
        intent.setClassName("com.example.aidlservertest","com.example.aidlservertest.Service.PersonService");
        bindService(intent,MyServerConnection, Context.BIND_AUTO_CREATE);
    }

    /**
     * 方法说明:创建ServiceConnection
     * 日期:2020-09-09 17:15
     */
    private ServiceConnection MyServerConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            System.out.println("---客户端 建立服务链接; Thread: "+Thread.currentThread().getName());
            //初始化远程iBinder实例,将iBinder转成远程服务代理对象,也就是PersonManagerProxy类对象,并调用它的方法
            personManagerInterface = Stub.asInterface(iBinder);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            System.out.println("---客户端 断开服务链接; Thread: "+Thread.currentThread().getName());
        }
    };
}
           
  1. 绑定服务中,Intent中传入的两个参数,一个是服务端的包名,一个是服务端Service的类路径;
  2. ServiceConnection类中onServiceConnected方法返回了一个iBinder对象,此时通过调用Stub.asInterface(iBinder)将iBInder转为服务端代理对象,也就是PersonManagerProxy接口实现类对象,并调用它的方法;

二、服务端

1、拷贝通信文件

将客户端的PersonManagerProxy、Proxy、Stub、PersonBean三个类,原封不动拷贝到服务端工程下,三个类所在目录也要同客户端一致;

2、创建Service

public class PersonService extends Service {

    private List<PersonBean> list = new ArrayList<>();

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("---服务端 onStartCommand; Thread: "+Thread.currentThread().getName());
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("---服务端 onBind; Thread: "+Thread.currentThread().getName());
        return mIBinder;
    }

    /**
     * 方法说明:
     * 日期:2020-09-09 11:26
     */
    private IBinder mIBinder = new Stub(){
        @Override
        public void addPerson(PersonBean personBean) throws RemoteException {
            if (personBean != null){
                list.add(personBean);
            }
            System.out.println("---服务端 addPerson; Thread: "+Thread.currentThread().getName()+", list: "+list);
        }
        @Override
        public void deletePerson(PersonBean personBean) throws RemoteException {
            list.remove(personBean);
            System.out.println("---服务端 deletePerson; Thread: "+Thread.currentThread().getName()+", list: "+list);
        }
        @Override
        public List<PersonBean> getPerson() throws RemoteException {
            System.out.println("---服务端 getPerson; Thread: "+Thread.currentThread().getName()+", list: "+list);
            return list;
        }
    };
}
           
  1. Service类中的onBind方法返回了一个IBinder对象,这里在Service类中实例化一个Stub对象,因为Stub继承了Binder,同时实现增加、删除、查询方法,在这三个方法中进行实现相应的功能,客户端通过Proxy——>Binder.transact——>Binder驱动——>服务端Stub.onTransact——服务端new Stub;形成一个完整的通信机制

3、服务端开启服务

public class MainActivity extends AppCompatActivity {

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

        startService(new Intent(this, PersonService.class));
    }
}
           

使用startService开启服务;

4、注册服务

<service android:name="com.example.aidlservertest.Service.PersonService"
                android:enabled="true"
                android:exported="true"/>
           

到此整个手动创建AIDL工程已经结束,测试的时候,需要先运行服务端,再运行客户端;