带有 Java 泛型的 Android AIDL

Dan*_*iel 5 java generics android aidl

Android AIDL 是否支持泛型?

例如,假设我有一个 class Result<T>,其中 T 可以是任何类型,包括原语(通过自动装箱)或其他自定义类,例如Car. 任何自定义类都Parcelable按照 Binder 的要求实现。

那么可能的 AIDL 方法签名将是

  • Result<Car> m1();
  • Result<Void> m2();
  • Result<Boolean> m3();

Dan*_*iel 6

据我所知,AIDL 编译器不喜欢Result<Animal> getResult();. 但是,Result getResult();确实有效。所以这就是我所做的:

  1. 创建了一个带有签名的类public class Result<T extends Parcelable> implements Parcelable
  2. 创建了一个新类以放入第一个名为 Animal 的类中。签名是public class Animal implements Parcelable
  3. 必须在 Result 和 Animal 中实现接口Parcelable和 a所需的方法CREATOR,并根据需要为每个方法创建一个 AIDL,并在主 AIDL 中导入这两个类。这些东西是常规的 AIDL 工作,在 AIDL站点中有描述。
  4. 在里面Result,我们不仅存储了一个类型的对象,T还存储了一个Class对象。在编写包裹时,我们需要先编写类类型,然后才是通用对象。阅读时,我们按照相同的顺序进行。我们需要编写类类型,因为当我们阅读时我们必须这样做t = (T) in.readValue(classType.getClassLoader());,如果没有类类型,我们不知道要获取哪个类加载器。可能还有其他方法可以做到这一点,但这就是我为这个例子所做的。
  5. 当客户端节点上接收,我可以做成功Result<Animal> r = MainActivity.this.service.getResult();,然后呼吁这两种方法ResultAnimal

可以在下面找到一些希望使事情更清晰的代码。

public class Result<T extends Parcelable> implements Parcelable {

    private String msg;
    private Class classType;
    private T value;

    public Result(String msg, T value, Class classType) {
        this.msg = msg;
        this.value = value;
        this.classType = classType;
    }

    // to reconstruct object
    public Result(Parcel in) {
        readFromParcel(in);
    }

    public String getMsg() {
        return msg;
    }

    public T getValue() {
        return value;
    }

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(msg);
        dest.writeValue(classType);
        dest.writeValue(value);
    }

    private void readFromParcel(Parcel in) {
        this.msg = in.readString();
        this.classType = (Class) in.readValue(Class.class.getClassLoader());
        this.value = (T) in.readValue(classType.getClassLoader());
    }

    public static final Creator<Result> CREATOR = new Creator<Result>() {
        @Override
        public Result createFromParcel(Parcel source) {
            return new Result(source);
        }

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


public class Animal implements Parcelable {

    private int n;

    public Animal(int n) {
        this.n = n;
    }

    public Animal(Parcel in) {
        readFromParcel(in);
    }

    public int getN() {
        return n;
    }

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

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

    private void readFromParcel(Parcel in) {
        n = in.readInt();
    }

    public static final Creator<Animal> CREATOR = new Creator<Animal>() {
        @Override
        public Animal createFromParcel(Parcel source) {
            return new Animal(source);
        }

        @Override
        public Animal[] newArray(int size) {
            return new Animal[size];
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

服务摘录:

@Override
public Result getResult() throws RemoteException {
    Result<Animal> r = new Result<Animal>("this is an animal", new Animal(42), Animal.class);
    return r;
}
Run Code Online (Sandbox Code Playgroud)

来自客户的摘录:

Result<Animal> r = MainActivity.this.service.getResult();

Log.d(TAG, "Received the following (Outer): " + r.getMsg());
Log.d(TAG, "Received the following (Inner): " + r.getValue().getN());
Run Code Online (Sandbox Code Playgroud)

另一种方法是更改Resultinto的签名public class Result<T extends Serializable> implements Parcelable,制作Animalimplement Serializable,然后在 Result 中使用dest.writeSerializable(value);and this.value = (T) in.readSerializable();

使用这种方法,不需要将类类型发送到另一端,甚至根本不需要使用它。尽管如此,你还是会付出代价