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

原创 2016年06月01日 13:21:10

问题来源

项目开发过程中,实体类实现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<DataEntity> CREATOR = new Creator<DataEntity>() {
        @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<DataEntity> CREATOR = new Creator<DataEntity>() {
        @Override
        public DataEntity createFromParcel(Parcel source) {
            return new DataEntity(source);
        }

        @Override
        public DataEntity[] newArray(int size) {
            return new DataEntity[size];
        }
    };
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

带泛型的parcelable序列化

Serializablepackage com.delta.news.model.entity;import java.io.Serializable;import android.os.Bundle...

Kotlin中泛型的序列化Parcelable

(转载)http://www.jianshu.com/p/e4bb5e23d9f5 系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正。如果你觉得我的文章对你有用,...

Android Parcelable实现类混淆

欢迎使用Markdown编辑器写博客项目开发已经接近尾声了,目前,希望通过混淆来保护自己的成果。以前也没怎么接触这个东西,很多相关混淆的东西不是很懂,正好公司有几个大牛还在,正好搞一下。 先声明一下...

Android使用Parcelable序列化复杂数据结构

前言说到序列化我们都不陌生,最简单的就是让我们的实体类来实现java io包下的Serializable接口即可,但是android单独又写了自己的序列化方案,即Parcelable,它比Serial...

AngularJs中POST和GET方式的ajax请求

angular中ajax请求的方法说明: /* * _http:angularJs中的$http对象 * _url:ajax请求的URL * _method:请求方式:POST或GET * _...

安卓服务——started service一个非绑定式服务

Started Service(非绑定服务) △本文将会向你讲述以下内容: →非绑定式服务定义,特点。 →如何启动,停止服务。 →生命周期方法说明。 →怎样创建一个你自己的服务。 →与你所创建的服务通...

android开发之Parcelable使用详解

想要在两个activity之间传递对象,那么这个对象必须序列化,android中序列化一个对象有两种方式,一种是实现Serializable接口,这个非常简单,只需要声明一下就可以了,不痛不痒。但是a...

Android使用Parcelable传递对象

在开发中,我们经常要通过Bundle来传递对象,而Bundle则提供了两个方法供我们调用,两个如下:putParcelable(String key, Parcelable value); putSe...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android中如何在Parcelable中使用泛型?
举报原因:
原因补充:

(最多只允许输入30个字)