android开发——跨进程通讯数据传递(三)

来源:互联网 发布:java求n的阶乘for循环 编辑:程序博客网 时间:2024/05/21 07:05

好了,承接上文,上问我们说道我们的新的需求——想要使得aidl能够传递可继承的类

aidl本身是不支持这样的,但是我们可以通过Parcelable进行构造的时候,去满足我们的需求

还记得在实现Parcelable时我们需要构造的其中一个静态类么?其中有这样的方法

public A createFromParcel(Parcel source) {              return new A(source);  }
这里也就是决定了我们要实际构造的对象,换言之,我们可以在这个部分知道需要构造的对象类型问题就解决了~


于是,我们可以在构造函数改造成这样,并且修改createFromParcel,当接收到数据去构造对象时,第一件事就是读取类名

注意,Parcel调用一次read方法后,就会移除该部分数据

public A(Parcel in) {        String className = in.readString();        try {            //赋值给当前对象            rehydrate(this, in);        } catch (IllegalArgumentException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }    public static final Parcelable.Creator<A> CREATOR = new Parcelable.Creator<A>() {        public A createFromParcel(Parcel in) {            Class<?> parceledClass;            try {                parceledClass = Class.forName(in.readString());                A model = (A) parceledClass.newInstance();                rehydrate(model, in);                return model;            } catch (ClassNotFoundException e) {                e.printStackTrace();            } catch (InstantiationException e) {                e.printStackTrace();            } catch (IllegalAccessException e) {                e.printStackTrace();            }            return null;        }        public A[] newArray(int size) {            return new A[size];        }    };    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeString(this.getClass().getName());        try {            //将当前对象写入到dest中            dehydrate(this, dest);        } catch (IllegalArgumentException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }


显然,现在的问题变成,我们通过rehydrate给对象赋值,通过dehydrate来将对象的数据写入

而这将依靠Class类中的newInstance()方法,之后通过反射,将对应数据进行复制

而为了能方便的写入对应字段的值,我们需要一个稳定的顺序,这里我们根据字段的类型来排序

完整的类A如下

public class A implements Parcelable {    public A() {    }    public A(Parcel in) {        String className = in.readString();        try {            //赋值给当前对象            rehydrate(this, in);        } catch (IllegalArgumentException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }    public static final Parcelable.Creator<A> CREATOR = new Parcelable.Creator<A>() {        public A createFromParcel(Parcel in) {            Class<?> parceledClass;            try {                parceledClass = Class.forName(in.readString());                A model = (A) parceledClass.newInstance();                rehydrate(model, in);                return model;            } catch (ClassNotFoundException e) {                e.printStackTrace();            } catch (InstantiationException e) {                e.printStackTrace();            } catch (IllegalAccessException e) {                e.printStackTrace();            }            return null;        }        public A[] newArray(int size) {            return new A[size];        }    };    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeString(this.getClass().getName());        try {            //将当前对象写入到dest中            dehydrate(this, dest);        } catch (IllegalArgumentException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }    //注意读取变量和写入变量的顺序应该一致 不然得不到正确的结果    public void readFromParcel(Parcel source) {        Class<?> parceledClass;        try {            parceledClass = Class.forName(source.readString());            A model = (A) parceledClass.newInstance();            rehydrate(this, source);        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }    @Override    public int describeContents() {        return 0;    }    protected static void dehydrate(A model, Parcel out) throws IllegalArgumentException, IllegalAccessException {        Field[] fields = model.getClass().getDeclaredFields();        Arrays.sort(fields, compareMemberByName);        for (Field field : fields) {            field.setAccessible(true);            if (field.getType().equals(int.class)) {                out.writeInt(field.getInt(model));            } else if (field.getType().equals(double.class)) {                out.writeDouble(field.getDouble(model));            } else if (field.getType().equals(float.class)) {                out.writeFloat(field.getFloat(model));            } else if (field.getType().equals(long.class)) {                out.writeLong(field.getLong(model));            } else if (field.getType().equals(String.class)) {                out.writeString((String) field.get(model));            } else if (field.getType().equals(boolean.class)) {                out.writeByte(field.getBoolean(model) ? (byte) 1 : (byte) 0);            } else if (A.class.isAssignableFrom(field.getType())) {                Log.e("GlobalParcelable", "GlobalParcelable F*ck up: " + " (" + field.getType().toString() + ")");                out.writeParcelable((A) field.get(model), 0);            } else {                Log.e("GlobalParcelable", "Could not write field to parcel: " + " (" + field.getType().toString() + ")");            }        }    }    protected static void rehydrate(A model, Parcel in) throws IllegalArgumentException, IllegalAccessException {        Field[] fields = model.getClass().getDeclaredFields();        Arrays.sort(fields, compareMemberByName);        // populate the fields        for (Field field : fields) {            field.setAccessible(true);            if (field.getType().equals(int.class)) {                field.set(model, in.readInt());            } else if (field.getType().equals(double.class)) {                field.set(model, in.readDouble());            } else if (field.getType().equals(float.class)) {                field.set(model, in.readFloat());            } else if (field.getType().equals(long.class)) {                field.set(model, in.readLong());            } else if (field.getType().equals(String.class)) {                field.set(model, in.readString());            } else if (field.getType().equals(boolean.class)) {                field.set(model, in.readByte() == 1);            } else if (A.class.isAssignableFrom(field.getType())) {                Log.e("GlobalParcelable", "read GlobalParcelable: " + " (" + field.getType().toString() + ")");                field.set(model, in.readParcelable(field.getType().getClassLoader()));            } else {                Log.e("GlobalParcelable", "Could not read field from parcel: " + field.getName() + " (" + field.getType().toString() + ")");            }        }    }    /*     * Comparator object for Members, Fields, and Methods     */    private static Comparator<Field> compareMemberByName =            new CompareMemberByName();    private static class CompareMemberByName implements Comparator {        public int compare(Object o1, Object o2) {            String s1 = ((Member) o1).getName();            String s2 = ((Member) o2).getName();            if (o1 instanceof Method) {                s1 += getSignature((Method) o1);                s2 += getSignature((Method) o2);            } else if (o1 instanceof Constructor) {                s1 += getSignature((Constructor) o1);                s2 += getSignature((Constructor) o2);            }            return s1.compareTo(s2);        }    }    private static String getSignature(Class clazz) {        String type = null;        if (clazz.isArray()) {            Class cl = clazz;            int dimensions = 0;            while (cl.isArray()) {                dimensions++;                cl = cl.getComponentType();            }            StringBuffer sb = new StringBuffer();            for (int i = 0; i < dimensions; i++) {                sb.append("[");            }            sb.append(getSignature(cl));            type = sb.toString();        } else if (clazz.isPrimitive()) {            if (clazz == Integer.TYPE) {                type = "I";            } else if (clazz == Byte.TYPE) {                type = "B";            } else if (clazz == Long.TYPE) {                type = "J";            } else if (clazz == Float.TYPE) {                type = "F";            } else if (clazz == Double.TYPE) {                type = "D";            } else if (clazz == Short.TYPE) {                type = "S";            } else if (clazz == Character.TYPE) {                type = "C";            } else if (clazz == Boolean.TYPE) {                type = "Z";            } else if (clazz == Void.TYPE) {                type = "V";            }        } else {            type = "L" + clazz.getName().replace('.', '/') + ";";        }        return type;    }    private static String getSignature(Method meth) {        StringBuffer sb = new StringBuffer();        sb.append("(");        Class[] params = meth.getParameterTypes(); // avoid clone        for (int j = 0; j < params.length; j++) {            sb.append(getSignature(params[j]));        }        sb.append(")");        sb.append(getSignature(meth.getReturnType()));        return sb.toString();    }    private static String getSignature(Constructor cons) {        StringBuffer sb = new StringBuffer();        sb.append("(");        Class[] params = cons.getParameterTypes(); // avoid clone        for (int j = 0; j < params.length; j++) {            sb.append(getSignature(params[j]));        }        sb.append(")V");        return sb.toString();    }}

至此,一个支持aidl继承功能的基类A就ok了~

接下来我们可以派生一个子类B,并通过aidl传递过去,再在binder线程中强制转化为类B进行输出

 这方面的代码就不贴出了,有心的读者可以自己尝试下

0 0
原创粉丝点击