Android中如何在Parcelable中使用泛型?

问题来源

项目开发过程中,实体类实现Parcelable接口是常见的事情,实体类除了要实现它的几个方法之外,还另外要定义一个静态常量CREATOR,如下例所示:

public class DataEntity<T extends Parcelable> implements Parcelable {
    private String str;
    private int position;
    private T data;

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.str);
        dest.writeInt(this.position);
        dest.writeParcelable(this.data, flags);
    }

    public DataEntity() {
    }

    protected DataEntity(Parcel in) {
        this.str = in.readString();
        this.position = in.readInt();
        this.data = in.readParcelable(T.class.getClassLoader());
    }

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

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

看完上面的代码,您觉得他会正常运行吗?答案肯定是不能,不然我也没必要写这篇文章了。

仔细观察上面代码就会发现这个实体类中有个泛型存在,泛型在反序列化的时候,没有具体类型,拿不到它的CREATOR!

所以如果拿不到CREATOR,那么就无法执行反序列化,同时Android系统的源码我们不能去修改,只能寻找其他的途径了。

错误的解决方案

网络流传了一种解决方案是:把泛型数据用Bundle包装,然后序列化和反序列化这个Bundle对象,进过测试发现这种方案行不通。代码如下:

 //write
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(DATA_KEY, data);
dest.writeBundle(bundle);

//read
this.data = in.readBundle().getParcelableArrayList(DATA_KEY);

最终解决方案

经过以上的分先发现,反序列化之所失败,就是因为我们拿不到泛型对应类的classLoader,那么从这个角度出发,我们是否可以序列化的时候先保存这个泛型的标准类名(报名+类名,例如:com.feeyo.DataEntity),然后再反序列化的时候利用Java 反射得到classLoader。有了思路,代码如下:

public class DataEntity<T extends Parcelable> implements Parcelable {
    private String str;
    private int position;
    private T data;

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

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.str);
        dest.writeInt(this.position);
        dest.writeString(data.getClass().getName());
        dest.writeParcelable(this.data, flags);
    }

    public DataEntity() {
    }

    protected DataEntity(Parcel in) {
        this.str = in.readString();
        this.position = in.readInt();
        String dataName = in.readString();
        try {
            this.data = in.readParcelable(Class.forName(dataName).getClassLoader());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

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

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

你可能感兴趣的:(Android学习心得)