【问题标题】:Android AIDL with Java generics带有 Java 泛型的 Android AIDL
【发布时间】:2015-01-20 18:05:24
【问题描述】:

Android AIDL 是否支持泛型?

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

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

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

【问题讨论】:

  • “Android AIDL 是否支持泛型?” - 不是我知道的,因为 AIDL 是跨语言的,不是特定于 Java 的,而且我不知道 C/C++ 将如何使用您想要的方法。如果ResultParcelable,那么您可能有Result m();

标签: java android generics aidl


【解决方案1】:

据我所知,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 中实现接口 ParcelableCREATOR 所需的方法,并根据需要为每个类创建一个 AIDL,并在主 AIDL 中导入这两个类。这些东西是常规的 AIDL 工作,在 AIDL site 中有描述。
  4. Result 中,我们不仅存储T 类型的对象,还存储Class 对象。在编写包裹时,我们需要先编写类类型,然后再编写通用对象。阅读时,我们按照相同的顺序进行。我们需要编写类类型,因为当我们阅读时,我们必须做t = (T) in.readValue(classType.getClassLoader());,而没有类类型我们do not know 要获取哪个类加载器。可能还有其他方法可以做到这一点,但这就是我在这个例子中的做法。
  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];
        }
    };
}

服务摘录:

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

客户摘录:

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());

另一种方法是将Result的签名更改为public class Result&lt;T extends Serializable&gt; implements Parcelable,使Animal实现Serializable,然后在Result中使用dest.writeSerializable(value);this.value = (T) in.readSerializable();

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

【讨论】:

  • 嗨丹尼尔,是否可以提供上述实现的链接或共享代码。抱歉,我无法完全实施您的方法。提前致谢!
  • 你真的需要传递classType吗?看起来你只是用它来获取类加载器。
【解决方案2】:

Daniels 解决方案几乎对我有用,除了编组和解组类类型的东西。 而不是“dest.writeValue(classType);""this.classType = (Class) in.readValue(Class.class.getClassLoader());" 我不得不使用 "dest.writeSerializable(classType);""classType = (Class) in.readSerializable();",它就像一个魅力

谢谢丹尼尔

【讨论】:

  • 谢谢 Teodor 和 Daniel :)
  • 你们拯救了我的一天!
猜你喜欢
  • 1970-01-01
  • 2014-12-14
  • 1970-01-01
  • 2021-08-01
  • 2017-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多