Android 进程间通信机制(六) 手写AIDL文件

  阅读本篇文章前, 请先查看一下笔者之前的写的两篇博客文章: Android Service知识  和  Android AIDL使用

        进程间通信涉及到客户端和服务端, 肯定有绑定服务的过程, 所以要阅读一下Android Service相关的知识,   跨进程通信的媒介aidl文件,我们也必须要了解怎么创建的,有什么规则,所以请先阅读一下Android AIDL使用这篇文章.

一. 概述

      

       本文重点讲解一下AIDL文件结构以及类中每个方法的含义.  然后把AIDL中每个方法的用途理解清楚后, 我们就不依赖AS自带的工具创建, 而是自己手动去写一个AIDL文件, 在手写的代码中添加自己的日志, 根据打印理清楚客户端与服务端跨进程通信的流程图, 目的加深对IPC机制的理解.

二. AIDL文件结构

 这是我创建的一个 IStudentService.aidl   里面有三个方法,然后build一下,系统自动为我们生成一个IStudentService.java类. 先大致看一下类结构和方法:

public interface IStudentService extends android.os.IInterface {
    /**
     * Default implementation for IStudentService.
     */
    public static class Default implements com.example.mysevicejava.IStudentService {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         *///定向tag
        @Override
        public java.lang.String getString() throws android.os.RemoteException {
            return null;
        }

        @Override
        public void addStudent(com.example.mysevicejava.Student student) throws android.os.RemoteException {
        }
        //void test(in PathParceTest obb);

        @Override
        public java.util.List<com.example.mysevicejava.Student> getStudentList() throws android.os.RemoteException {
            return null;
        }

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

    /**
     * Local-side IPC implementation stub class.
     * 1. Stub是一个抽象类 最终的实现是在service中.
     * 2. 同时继承拓展了android.os.Binder.
     * 3. Stub 是 IStudentService接口的具体实现类.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.mysevicejava.IStudentService {
        private static final java.lang.String DESCRIPTOR = "com.example.mysevicejava.IStudentService";

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

        /**
         * Cast an IBinder object into an com.example.mysevicejava.IStudentService interface,
         * generating a proxy if needed.
这个是方法是在静态抽象类 Stub中,  作用: 用于服务端的Binder对象转换成客户端所需的AIDL接口类型的对象, 此转换过程是区分进程的,如果Client 和 Service端在统一进程中, 那么此方法返回的就是服务端的Stub对象本身, 如果是跨进程的话, 则返回的是Stub.proxy对象.
         */
        public static com.example.mysevicejava.IStudentService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.mysevicejava.IStudentService))) {
                return ((com.example.mysevicejava.IStudentService) iin);
            }
            return new com.example.mysevicejava.IStudentService.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 {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_getString: {
                    data.enforceInterface(descriptor);
                    java.lang.String _result = this.getString();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
                case TRANSACTION_addStudent: {
                    data.enforceInterface(descriptor);
                    com.example.mysevicejava.Student _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.example.mysevicejava.Student.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addStudent(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getStudentList: {
                    data.enforceInterface(descriptor);
                    java.util.List<com.example.mysevicejava.Student> _result = this.getStudentList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.example.mysevicejava.IStudentService {
            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.
             *///定向tag
            @Override
            public java.lang.String getString() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    boolean _status = mRemote.transact(Stub.TRANSACTION_getString, _data, _reply, 0);
                    if (!_status && getDefaultImpl() != null) {
                        return getDefaultImpl().getString();
                    }
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void addStudent(com.example.mysevicejava.Student student) 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 ((student != null)) {
                        _data.writeInt(1);
                        student.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    boolean _status = mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);
                    if (!_status && getDefaultImpl() != null) {
                        getDefaultImpl().addStudent(student);
                        return;
                    }
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
            //void test(in PathParceTest obb);

            @Override
            public java.util.List<com.example.mysevicejava.Student> getStudentList() 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.mysevicejava.Student> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    boolean _status = mRemote.transact(Stub.TRANSACTION_getStudentList, _data, _reply, 0);
                    if (!_status && getDefaultImpl() != null) {
                        return getDefaultImpl().getStudentList();
                    }
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.example.mysevicejava.Student.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            public static com.example.mysevicejava.IStudentService sDefaultImpl;
        }

        static final int TRANSACTION_getString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_getStudentList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);

        public static boolean setDefaultImpl(com.example.mysevicejava.IStudentService impl) {
            if (Stub.Proxy.sDefaultImpl == null && impl != null) {
                Stub.Proxy.sDefaultImpl = impl;
                return true;
            }
            return false;
        }

        public static com.example.mysevicejava.IStudentService getDefaultImpl() {
            return Stub.Proxy.sDefaultImpl;
        }
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     *///定向tag
    public java.lang.String getString() throws android.os.RemoteException;

    public void addStudent(com.example.mysevicejava.Student student) throws android.os.RemoteException;
    //void test(in PathParceTest obb);

    public java.util.List<com.example.mysevicejava.Student> getStudentList() throws android.os.RemoteException;
}

根据类结构图, 其实我们只需要搞明白这2个核心实现方法

1. 静态抽象类 Stub;

2. Stub的静态内部类Proxy ;

Question:  写到这里,提个问题,就是google工程师为什么要把 Stub类设计为抽象类啊?

Answer:   Stub类extends  android.os.Binder  并且 implement 你自定义的AIDL文件中的方法,  它的最终实现是在你的service代码中,  人家google工程师他们只能帮你把模板搭建好, 具体的业务逻辑肯定是自己去实现了.

在服务端中继承IStudentService.Stub这个抽象类, 并在 onBind回调方法中返回IBinder对象

    class MyBinder extends IStudentService.Stub{

        @Override
        public String getString() throws RemoteException {
            return "我是从服务端返回的数据:  111";
        }

        @Override
        public void addStudent(Student student) throws RemoteException {
            mStudentList.add(student);
        }

        @Override
        public List<Student> getStudentList() throws RemoteException {
            return mStudentList;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.e("test", "==服务端==onBind========");
        // TODO: Return the communication channel to the service.
        return new MyBinder();
    }

这个IBinder对象对应的就是客户端中 IBinder  service对象.

public void onServiceConnected(ComponentName componentName, IBinder service)

我们逐个来解析:

public interface IStudentService extends android.os.IInterface

2.1  首先IStudentService.java类继承与 IInterface这个接口

package android.os;

/**
 * Base class for Binder interfaces.  When defining a new interface,
 * you must derive it from IInterface.

    Binder接口的基类。当定义新接口时,你必须继承它。
 */
public interface IInterface
{
    /**
     * Retrieve the Binder object associated with this interface.
     * You must use this instead of a plain cast, so that proxy objects
     * can return the correct result.

    检索与此接口关联的Binder对象。

    必须使用此方法转换,这样代理对象才能返回正确的结果

     */
    public IBinder asBinder();
}

同时它自己也是一个接口, 所有可以在Binder中传输的接口都需要继承IInterface接口, 那么如果要自定义手写AIDL的话, 我们当然必须继承IInterface接口, 好到这里提炼第一条规则出来.

2.2  Binder的唯一标识, 一般用当前Binder的类名表示.

为了一个Binder和一个特定服务接口绑定,以对外提供功能,需要给Binder定义一个DESCRIPTOR描述,表示我这个Binder是提供特定功能链接的,不是随便可以用的。

通常,DESCRIPTOR描述会直接使用包名 + 服务接口

private static final java.lang.String DESCRIPTOR = "com.example.mysevicejava.IStudentService";

2.3   asInterface(android.os.IBinder obj)

        这个是方法是在静态抽象类 Stub中,  作用: 用于服务端的Binder对象转换成客户端所需的AIDL接口类型的对象, 此转换过程是区分进程的,如果Client 和 Service端在统一进程中, 那么此方法返回的就是服务端的Stub对象本身, 如果是跨进程的话, 则返回的是Stub.proxy对象.

 public static com.example.mysevicejava.IStudentService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
// queryLocalInterface是Binder的方法,搜索本地是否有可用的对象
// DESCRIPTOR = "com.example.mysevicejava.IStudentService";
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

             //如果有,则强制类型转换并返回
            if (((iin != null) && (iin instanceof com.example.mysevicejava.IStudentService))) {
                return ((com.example.mysevicejava.IStudentService) iin);
            }
// //如果没有,则构造一个IStudentService.Stub.Proxy对象
            return new com.example.mysevicejava.IStudentService.Stub.Proxy(obj);
        }

2.4   Stub的静态内部类Proxy

通过上面的new com.example.mysevicejava.IStudentService.Stub.Proxy(obj)调用过来的

private static class Proxy implements com.example.mysevicejava.IStudentService{

      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;
      }
      .......
      .......
}

通过代码,我们知道

1. Proxy 实现了 com.example.mysevicejava.IStudentService 里面的3个方法

2. Proxy的asBinder()方法返回的mRemote,  mRemote是在Proxy(android.os.IBinder remote) 这个构造方法中赋值的.  

3.  网上有另外的一种结论:

asInterface方法的主要作用:如果是多进程操作,参数obj是BinderProxy对象,就new一个proxy接口;通过调用new com.example.mysevicejava.IStudentService.Stub.Proxy(obj) 就可以知道

BinderProxy对象保存到mRemote变量,mRemote在aidl中是一个辅助变量.

mRemote 就是 BinderProxy对象.

----- 这条结论再后面的文章中验证.先记住就可以了,

三. Stub 和 Proxy 理解

首先从字面上来理解一下: proxy是代理   Stub是存根

AIDL:  Android interface Definition Language

如果你觉的AIDL中的proxy / stub 比较难理解的话,先触类旁通一下, 换个思维理解 

MIDL:微软接口定义语言Microsoft interface Definition Language, 它是定义COM接口的说明性语言。 关于COM (Component Object Model),中文译为,组件对象模型, 它也是一种进程间通信接口, 具体用法参考: 理解Com(Component Object model)  这篇文章,但不是我们关注的重点, 我们只是借助于它来理解我们的AIDL中的 proxy-stub 模式 , 拿COM的通信模式图看一下:

打个比方,你到自动取款机上去取款

你不会在乎钱具体放在那里,你只想看到足够或更多的钱从出口出来(这就是com的透明性)。你同银行之间的操作完全是取款机代理实现。你的取款请求通过取款机,传到另一头,银行的服务器,他也没有必要知道你在哪儿取钱,他所关心的是你的身份,和你取款多少。当他确认你的权限,就进行相应的操作,返回操作结果给取款机,取款机根据服务器返回结果,从保险柜里取出相应数量的钱给你。你取出卡后,操作完成。取款机不是直接同服务器连接的,他们之间还有一个“存根”,取款机与存根通信,存根又与服务器通信。从某种意义上说存根就是服务器的代理。(参考COM代理与存根)

概念理解: 

  客户端:  自己

  proxy : 取款机 ,可以理解为银行金融系统取款业务的代理

  服务端: 银行金融系统

  Stub:   取款凭证(显示交易时间,交易金额,存钱/取钱),  它作为银行金融系统的实体存根

再回到AIDLFramework层的架构,如下图:


换而言之,Android就是在传统的C/S架构中加入了一层,实现IPC。图中表明,AIDL类似COM的Proxy/Stub架构。不过是现在android自己的序列化类Pacel。

客户端的代码中调用

 @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.e("test", " componentName  :" + componentName);
            mIStudentService = IStudentService.Stub.asInterface(iBinder);
        }

我们再回到2.3 asInterface(android.os.IBinder obj) 这个方法中来

asInterface():客户端在ServiceConnection通过IStudentService.Stub.asInterface(IBinder),
会根据是同一进行通信, 还是不同进程通信,返回Stub()实体,或者Stub.Proxy()代理对象

从字面意思看,Stub是存根,Proxy是代理,而这个Stub是谁的存根呢?Proxy又是谁的代理呢?


我理解的是 :  

Stub是 服务端Binder实体的存根.

Proxy则是Stub的代理. 

Stub类: 服务实体,Binder的实现类,服务端一般会实例化一个Binder对象,在服务端onBind中绑定, 客户端asInterface获取到Stub。 这个类在编译aidl文件后自动生成,它继承自Binder,表示它是一个Binder本地对象; 它是一个抽象类,实现了IInterface接口,表明它的子类需要实现Server将要提供的具体能力(即aidl文件中声明的方 法)

Stub.Proxy类: 服务的代理,客户端asInterface获取到Stub.Proxy。 它实现了IInterface接口,说明它是 Binder通信过程的一部分;它实现了aidl中声明的方法,但最终还是交由其中的mRemote成员来处理,说明它是一 个代理对象,mRemote成员实际上就是BinderProxy。供客户端来调用.
通信图:

四. 手写AIDL

我们先来看一下代码目录结构: 

分为4个部分:客户端, 服务端 , 手写AIDL文件, javabean类
 

直接上代码:

1. 客户端ClientActivity.java

/**
 * @ProjectName: WriteAIDLTest
 * @PackageName: com.example.writeaidltest
 * @Description: java类作用描述
 * @Author: 作者名
 * @CreateDate: 23-3-13 下午1:55
 * @Version: 1.0
 */
public class ClientActivity extends Activity {

    private Intent intent;

    private IStudent mIStudent;

    //是否绑定成功
    boolean mBound = false;


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

        intent = new Intent(this, MyServer.class);

        Button btn = (Button)findViewById(R.id.button);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mBound) {
                    try {
                        Log.e("test", "mIStudent.getString() 当前线程 :" +   Thread.currentThread().getName());
                        String text = mIStudent.getString();
                        Log.e("test", "mIStudent.getString() after ");
                        Toast.makeText(ClientActivity.this, "内容: " + text, Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });


        Button btn1 = (Button)findViewById(R.id.button1);
        btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mBound) {
                    try {
                        mIStudent.addStudent(new Student(3, "王五"));
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Button btn2 = (Button)findViewById(R.id.button2);
        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mBound) {
                    try {
                        Log.e("test", "获取服务端所有学生的信息:   "+mIStudent.getStudentList());
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

    }



    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            Log.e("test", "===客户端===onServiceConnected=====service是一个什么对象: ="+service.getClass().getCanonicalName());
            mBound = true;
            mIStudent = Stub.asInterface(service);
            Log.e("test", "===客户端 mIStudent是一个什么对象:" + mIStudent.getClass().getCanonicalName());
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.e("test", "====onServiceDisconnected=====");
            mBound = false;
        }
    };

    //在onstart方法中 调用 bindservice 绑定服务
    @Override
    protected void onStart() {
        super.onStart();
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    //在onstop方法中, 调用unbindservice 解绑服务
    @Override
    protected void onStop() {
        super.onStop();
        unbindService(connection);
        mBound = false;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

2.  服务端代码MyServer.java

/**
 * @ProjectName: WriteAIDLTest
 * @PackageName: com.example.writeaidltest.service
 * @Description: java类作用描述
 * @Author: 作者名
 * @CreateDate: 23-3-13 下午3:12
 * @Version: 1.0
 */
public class MyServer extends Service {

    private List<Student> mStudentList = new ArrayList<>();

    @Override
    public void onCreate() {
        super.onCreate();
        mStudentList.add(new Student(1, "张三"));
        mStudentList.add(new Student(2, "李四"));
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("test", "==服务端==onBind===new MyBinder()是一个什么对象====="+new MyBinder().getClass().getCanonicalName());
        //return new MyBinder();
        Log.e("test", "==服务端==onBind==myBinder是一个什么对象====="+myBinder.toString());
        return myBinder;
    }

    IBinder myBinder = new Stub() {
        @Override
        public String getString() throws RemoteException {
            return "服务端数据  777";
        }

        @Override
        public void addStudent(Student student) throws RemoteException {
            mStudentList.add(student);
        }

        @Override
        public List<Student> getStudentList() throws RemoteException {
            return mStudentList;
        }
    };

    class MyBinder extends Stub{
        @Override
        public String getString() throws RemoteException {
            return "服务端数据  111";
        }

        @Override
        public void addStudent(Student student) throws RemoteException {
            mStudentList.add(student);
        }

        @Override
        public List<Student> getStudentList() throws RemoteException {
            return mStudentList;
        }
    }

    @Override
    public void onDestroy() {
        Log.e("test", "==服务端=onDestroy=====");
        super.onDestroy();
    }



}

3.  序列化 Student.java

public class Student implements Parcelable {

    private int id;
    private String name;

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

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

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

    public void readFromParcel(Parcel parcel) {
        this.id = parcel.readInt();
        this.name = parcel.readString();
    }

    public static Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel source) {
            return new Student(source);
        }

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

    private Student(Parcel in) {
        this.id = in.readInt();
        this.name = in.readString();
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

4. 最重要,手动仿写AIDL文件  IStudent.java 

相当于 IStudent.aidl 文件用安卓自带工具生成  IStudent.java 

/**
 * @ProjectName: WriteAIDLTest
 * @PackageName: com.example.writeaidltest.aidlfile
 * @Description: 手动仿写AIDL文件
 * @Author: 作者名
 * @CreateDate: 23-3-13 下午1:58
 * @Version: 1.0
 */

public interface IStudent extends android.os.IInterface {
    //定义一个DESCRIPTOR
    //意图: 为了一个Binder和一个特定服务接口绑定,以对外提供功能,需要给Binder定义一个DESCRIPTOR描述,表示我这个Binder是提供特定功能链接的,不是随便可以用的
    public static final java.lang.String DESCRIPTOR = "com.example.writeaidltest.aidlfile.IStudentService";


    //定义操作数据的方法
    //1. 从服务端获取一个简单的字符串
    String getString() throws RemoteException;

    //2. 客户端往服务端 添加student对象
    void addStudent(Student student) throws RemoteException;

    //3. 客户端从服务段获取 所有Student的信息
    List<Student> getStudentList() throws RemoteException;




    //定义方法的id号
    static final int TRANSACTION_getString = IBinder.FIRST_CALL_TRANSACTION + 0;
    static final int TRANSACTION_addStudent = IBinder.FIRST_CALL_TRANSACTION + 1;
    static final int TRANSACTION_getStudentList = IBinder.FIRST_CALL_TRANSACTION + 2;
}

手动仿写AIDL文件   Stub.java

抽象类 Stub

public abstract class Stub extends android.os.Binder implements IStudent{

    //构造方法
    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }

    public static IStudent asInterface(IBinder obj) {

        if (obj == null) {
            return null;
        }

        IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (iin != null && (iin instanceof IStudent)) {
            return (IStudent)iin;
        }

        // 传入binder对象,返回一个服务代理对象
        return new Proxy(obj);

    }

    @SuppressLint("NewApi")
    @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 TRANSACTION_getString:
                // 获取IBinder接口标志
                data.enforceInterface(DESCRIPTOR);
                //这个是服务端自己实现getString方法,获取返回值
                String stringResult = this.getString();
                Log.e("test", " stub onTransact 当前线程: "+Thread.currentThread().getName());
                reply.writeNoException();
                reply.writeString(stringResult);
                return true;

            case TRANSACTION_addStudent:
                // 获取IBinder接口标志
                data.enforceInterface(DESCRIPTOR);
                // 获取传入的Student对象
                Student arg0 = null;
                if (data.readInt() != 0) {
                    arg0 = Student.CREATOR.createFromParcel(data);
                }
                this.addStudent(arg0);
                reply.writeNoException();
                return true;

            case TRANSACTION_getStudentList:
                data.enforceInterface(DESCRIPTOR);
                //
                List<Student> studentList = null;
                studentList = this.getStudentList();
                reply.writeNoException();
                reply.writeTypedList(studentList);
                return true;
        }
        return super.onTransact(code, data, reply, flags);
    }

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

手动仿写  Proxy.java 

public class Proxy implements IStudent{

    private IBinder mRemote;

    public Proxy(IBinder remote) {
        mRemote = remote;
        Log.e("test", "===Proxy中 mRemote 是一个什么对象: " + mRemote.getClass().getCanonicalName());
    }



    @Override
    public String getString() throws RemoteException {

        Parcel data = Parcel.obtain(); // 跨进程传输数据对象
        Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
        java.lang.String _result;
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            // 调Stub的onTransact方法进行Stub.TRANSACTION_getString,远端返回
            Log.e("test", "mRemote transact 当前线程 :" +   Thread.currentThread().getName());
            mRemote.transact(TRANSACTION_getString, data, reply, 0);

            reply.readException();
            _result = reply.readString();

        }finally {
            data.recycle();
            reply.recycle();
        }
        return _result;
    }

    @Override
    public void addStudent(Student student) throws RemoteException {
        Parcel data = Parcel.obtain(); // 跨进程传输数据对象
        Parcel reply = Parcel.obtain(); // 跨进程传输返回结果
        try{
            // 写入IBinder接口标志,一般为全类名,用户数据校验
            data.writeInterfaceToken(DESCRIPTOR);
            if (student != null){
                //写入数据
                data.writeInt(1);
                student.writeToParcel(data, 0);
            } else {
                data.writeInt(0);
            }
            // 调Stub的onTransact方法进行Stub.TRANSACTION_addBook处理,远端返回
            mRemote.transact(Stub.TRANSACTION_addStudent, data, reply, 0);
            reply.readException();
        } finally {
            data.recycle();
            reply.recycle();
        }
    }

    @Override
    public List<Student> getStudentList() throws RemoteException {
        Parcel data = Parcel.obtain(); // 跨进程传输数据对象
        Parcel reply = Parcel.obtain(); // 跨进程传输返回结果

        List<Student> result;
        try {
            // 写入IBinder接口标志,一般为全类名,用户数据校验
            data.writeInterfaceToken(DESCRIPTOR);
            // 调Stub的onTransact方法进行Stub.TRANSACTION_getStudentList,远端返回
            mRemote.transact(TRANSACTION_getStudentList, data, reply, 0);
            reply.readException();
            result = reply.createTypedArrayList(Student.CREATOR);
        } finally {
            reply.recycle();
            data.recycle();
        }

        return result;
    }


    // 返回Stub类传入的Binder对象
    @Override
    public IBinder asBinder() {
        return mRemote;
    }

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

清单AndroidManifest.xml 文件
 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.writeaidltest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.WriteAIDLTest">
        <activity android:name=".client.ClientActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- service 运行在另外一个进程中 -->
        <service
            android:name=".service.MyServer"
            android:exported="true"
            android:enabled="true"
            android:process=":remote">
            <intent-filter>
                <action android:name="com.my.binder" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>
    </application>

上面的例子是模拟进程间通信的整个过程,可以通过log看出客户端发送数据给服务端,然后服务端处理之后再返回给客户端的整个流程。

大家可以通过这个Demo去学习AIDL的原理,供参考!

Demo 已上传: https://download.csdn.net/download/u012514113/87906468

猜你喜欢

转载自blog.csdn.net/u012514113/article/details/129473916