AIDL中的in,out,inout用法篇

Android两个进程间内存相互独立不能互相访问,跨进程传输非默认类型对象需要先序列化,而不能直接简单传递引用,序列化的目的是将对象数据以能够在内存中流通的形式从一个进程传递到另一个进程,两个进程对象的传递类似深度clone,client端将对象数据写入Parcel(writeToParcel),server端从Parcel(readFromParcel)读取对象数据并重新创建一个同样的对象将读取到的数据填充到此对象,但这两个对象并不是一样的,只是他们的数据完全一样。

in,out,inout

两个进程中要传递的对象必须实现Parcelable接口,AIDL中序列化的对象传递还必须指定定向tag,tag表示数据的流通方向。
in:由cilent端流向server端,server端可以收到此对象的所有数据,收到之后会重新创建一个新的对象将数据填充进去,因为cilent端和server端是两个不同的对象,所以server端对数据的修改不会影响到client端的对象。
out:由server端流向client端,client端将对象传递给server端后,server端相当于收到的是一个空对象,没有client端此对象的任何数据,但是server端对此空对象的操作会影响到cilent端。
inout:对象可以双向流动,即server端能收到cilent发过来的对象的数据,server端对此对象的操作也能影响到cilent端

接下来用代码演示下三种tag的用法

定义三个传输对象的AIDL文件,Student.aidlTeacher.aidlWorker.aidl,三个对应java文件Student.javaTeacher.javaWorker.java并实现Parcelable序列化接口,跨进程传输的对象的定义规则就是一个java类对应一个aidl文件,这个三个对象文件分别用来演示in,out,inout三种tag

Student.aidl


package com.tct.aidlapplication;
parcelable Student;

Teacher.aidl


package com.tct.aidlapplication;
parcelable Teacher;

Worker.aidl


package com.tct.aidlapplication;
parcelable Worker;

Student .java

package com.tct.aidlapplication;

import android.os.Parcel;
import android.os.Parcelable;

public class Student implements Parcelable {
    public int age;
    public String name;
    public Student(){}
    public Student(int age,String name){
         this.age = age;
         this.name = name;
    }
    private Student(Parcel in) {
        readFromParcel(in);
    }
    //server端收到client端的数据后用Creator来构造server端的一个新对象
    public static final Creator<Student> CREATOR = new Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel in) {
            return new Student(in);
        }

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

    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(this.age);
        out.writeString(this.name);
    }
    public void readFromParcel(Parcel in){
        this.age = in.readInt();
        this.name = in.readString();
    }
}

Teacher .java

package com.tct.aidlapplication;

import android.os.Parcel;
import android.os.Parcelable;

public class Teacher implements Parcelable {
    public int age;
    public String name;
    public Teacher(){}
    public Teacher(int age,String name){
        this.age = age;
        this.name = name;
    }
    private Teacher(Parcel in) {
        readFromParcel(in);
    }
    //server端收到client端的数据后用Creator来构造server端的一个新对象
    public static final Creator<Teacher> CREATOR = new Creator<Teacher>() {
        @Override
        public Teacher createFromParcel(Parcel in) {
            return new Teacher(in);
        }

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

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

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(this.age);
        out.writeString(this.name);
    }
    public void readFromParcel(Parcel in){
        this.age = in.readInt();
        this.name = in.readString();
    }
}

Worker .java

package com.tct.aidlapplication;

import android.os.Parcel;
import android.os.Parcelable;

public class Worker implements Parcelable {
    public int age;
    public String name;
    public Worker(){}
    public Worker(int age, String name){
         this.age = age;
         this.name = name;
    }
    private Worker(Parcel in) {
        readFromParcel(in);
    }
    //server端收到client端的数据后用Creator来构造server端的一个新对象
    public static final Creator<Worker> CREATOR = new Creator<Worker>() {
        @Override
        public Worker createFromParcel(Parcel in) {
            return new Worker(in);
        }

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

    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(this.age);
        out.writeString(this.name);
    }
    public void readFromParcel(Parcel in){
        this.age = in.readInt();
        this.name = in.readString();
    }
}

可以看到这序列化对象都是同样的格式
接着定义再一个AIDL文件IAIDLControl.aidl,申明server端方法,由client端调用将对象传递过去
要注意传递的对象Student,Teacher ,Worker 在同一个包中也需要引入

IAIDLControl.aidl

// IAIDLControl.aidl
package com.tct.aidlapplication;
// Declare any non-default types here with import statements
import com.tct.aidlapplication.Student;
import com.tct.aidlapplication.Teacher;
import com.tct.aidlapplication.Worker;
interface IAIDLControl {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
     void addStudent(in Student student);
     void addTeacher(out Teacher teacher);
     void addWorker(inout Worker worker);

}

创建完成之后点击Android Studio的make project或者clean或者快捷键Ctrl+F9重新编译一下项目就会自动生成一系列代码如下:我是进行了格式化的,系统生成的可读性很差

IAIDLControl.java

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.tct.aidlapplication;

public interface IAIDLControl extends android.os.IInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public void addStudent(com.tct.aidlapplication.Student student)
            throws android.os.RemoteException;

    public void addTeacher(com.tct.aidlapplication.Teacher teacher)
            throws android.os.RemoteException;

    public void addWorker(com.tct.aidlapplication.Worker worker)
            throws android.os.RemoteException;

    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.tct.aidlapplication.IAIDLControl {
        private static final java.lang.String DESCRIPTOR = "com.tct.aidlapplication.IAIDLControl";
        static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION +
                0);
        static final int TRANSACTION_addTeacher = (android.os.IBinder.FIRST_CALL_TRANSACTION +
                1);
        static final int TRANSACTION_addWorker = (android.os.IBinder.FIRST_CALL_TRANSACTION +
                2);

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

        /**
         * Cast an IBinder object into an com.tct.aidlapplication.IAIDLControl interface,
         * generating a proxy if needed.
         */
        public static com.tct.aidlapplication.IAIDLControl asInterface(
                android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }

            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

            if (((iin != null) &&
                    (iin instanceof com.tct.aidlapplication.IAIDLControl))) {
                return ((com.tct.aidlapplication.IAIDLControl) iin);
            }

            return new com.tct.aidlapplication.IAIDLControl.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_addStudent: {
                    data.enforceInterface(descriptor);

                    com.tct.aidlapplication.Student _arg0;

                    if ((0 != data.readInt())) {
                        _arg0 = com.tct.aidlapplication.Student.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }

                    this.addStudent(_arg0);
                    reply.writeNoException();

                    return true;
                }

                case TRANSACTION_addTeacher: {
                    data.enforceInterface(descriptor);

                    com.tct.aidlapplication.Teacher _arg0;
                    _arg0 = new com.tct.aidlapplication.Teacher();
                    this.addTeacher(_arg0);
                    reply.writeNoException();

                    if ((_arg0 != null)) {
                        reply.writeInt(1);
                        _arg0.writeToParcel(reply,
                                android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    } else {
                        reply.writeInt(0);
                    }

                    return true;
                }

                case TRANSACTION_addWorker: {
                    data.enforceInterface(descriptor);

                    com.tct.aidlapplication.Worker _arg0;

                    if ((0 != data.readInt())) {
                        _arg0 = com.tct.aidlapplication.Worker.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }

                    this.addWorker(_arg0);
                    reply.writeNoException();

                    if ((_arg0 != null)) {
                        reply.writeInt(1);
                        _arg0.writeToParcel(reply,
                                android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    } else {
                        reply.writeInt(0);
                    }

                    return true;
                }

                default:return super.onTransact(code, data, reply, flags);
            }
        }

        private static class Proxy implements com.tct.aidlapplication.IAIDLControl {
            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 void addStudent(com.tct.aidlapplication.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);
                    }

                    mRemote.transact(Stub.TRANSACTION_addStudent, _data,
                            _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public void addTeacher(com.tct.aidlapplication.Teacher teacher)
                    throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_addTeacher, _data,
                            _reply, 0);
                    _reply.readException();

                    if ((0 != _reply.readInt())) {
                        teacher.readFromParcel(_reply);
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public void addWorker(com.tct.aidlapplication.Worker worker)
                    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 ((worker != null)) {
                        _data.writeInt(1);
                        worker.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }

                    mRemote.transact(Stub.TRANSACTION_addWorker, _data, _reply,
                            0);
                    _reply.readException();

                    if ((0 != _reply.readInt())) {
                        worker.readFromParcel(_reply);
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
    }
}

IAIDLControl.java的代码我们等下回过头来看,接着创建AIDLService对IAIDLControl的方法具体实现,三个方法实现都一样,打印一句log并且修改传递过来对象的属性值
注意AIDLService在Androidmanifests文件中文件中需要配置android:process=“com.aidl”,要和client端Activity处于不同进程

AIDLService.java

package com.tct.aidlapplication;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.Nullable;

public class AIDLService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return stub;
    }
    private  IAIDLControl.Stub stub = new IAIDLControl.Stub() {
        @Override
        public void addStudent(Student student) throws RemoteException {
            Log.d("dongjiao","in student addStudent...age = :"+student.age+",name = :"+student.name);
            student.age = 35;
            student.name = "Tom_update";
        }

        @Override
        public void addTeacher(Teacher teacher) throws RemoteException {
            Log.d("dongjiao","out teacher addTeacher age = :"+teacher.age+",name = :"+teacher.name);
            teacher.age = 35;
            teacher.name = "Jerry_update";
        }
        @Override
        public void addWorker(Worker worker) throws RemoteException {
            Log.d("dongjiao","inout worker addWorker age = :"+worker.age+",name = :"+worker.name);
            worker.age = 45;
            worker.name = "tony_update";
        }
    };
}

接着创建MainActivity用于调用这三个方法,activity_main放了三个Button分别调用AIDLService的三个方法,分别创建Student,Teacher,Worker对象传递给AIDLService

MainActivity.java

package com.tct.aidlapplication;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
    public Button button1;
    public Button button2;
    public Button button3;
    public IAIDLControl mIAIDLControl;
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mIAIDLControl = IAIDLControl.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button1 = findViewById(R.id.button1);
        button2 = findViewById(R.id.button2);
        button3 = findViewById(R.id.button3);
        Intent intent = new Intent(this,AIDLService.class);
        this.bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
        final Student student = new Student(20,"Tom");
        final Teacher teacher = new Teacher(30,"Jerry");
        final Worker worker = new Worker(40,"Tony");
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.d("dongjiao","before in student age = :"+student.age+",name = :"+student.name);
                    mIAIDLControl.addStudent(student);
                    Log.d("dongjiao","before in student age = :"+student.age+",name = :"+student.name);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.d("dongjiao","before out teacher age = :"+teacher.age+",name = :"+teacher.name);
                    mIAIDLControl.addTeacher(teacher);
                    Log.d("dongjiao","end out teacher age = :"+teacher.age+",name = :"+teacher.name);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Log.d("dongjiao","before inout worker age = :"+worker.age+",name = :"+worker.name);
                    mIAIDLControl.addWorker(worker);
                    Log.d("dongjiao","end inout worker age = :"+worker.age+",name = :"+worker.name);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

}

这三个方法都是在Activity调用addXXXX前后以及AIDLService此方法中打印log并修改传递过来的对象的属性,验证三种tag方式client端传递到server端的对象数据是否为空以及AIDLService修改数据之后是否对client端对象由影响

log验证

在这里插入图片描述
我们来看三个Button依次点击一次打印的log:

D/dongjiao( 2501): before in student age = :20,name = :Tom
D/dongjiao( 2517): in student addStudent...age = :20,name = :Tom
D/dongjiao( 2501): before in student age = :20,name = :Tom

D/dongjiao( 2501): before out teacher age = :30,name = :Jerry
D/dongjiao( 2517): out teacher addTeacher age = :0,name = :null
D/dongjiao( 2501): end out teacher age = :35,name = :Jerry_update

D/dongjiao( 2501): before inout worker age = :40,name = :Tony
D/dongjiao( 2517): inout worker addWorker age = :40,name = :Tony
D/dongjiao( 2501): end inout worker age = :45,name = :tony_update


可以看到定义tag为in时server端收到了cilent端的数据,并且在server端对数据的修改不能影响到client端对象,定向tag为out时server端收到的是一个空对象,并且server端对数据的修改能够影响到client端,定向tag为inout时server端既能收到client端的对象数据,并且对数据的修改也能影响到client端

到此AIDL三种tag的用法就已经讲解完了,后一篇文章会对三种tag原理进行讲解

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值