美文网首页
Android 序列化 - Serializable、Parce

Android 序列化 - Serializable、Parce

作者: lisheny | 来源:发表于2018-06-08 19:31 被阅读0次
    序列化:在数据传输中,如果要传输的是对象,这时候就用到我们的序列化和反序列化。有时候想将对象持久化储存在设备或者网络上,这时建议使用 Serializable
    • Serializable : java 提供的接口 ,使用简单,直接实现这个接口就行。下面是一个使用栗子。
    public class User implements Serializable {
       private static final long serialVersionUID = 1L; // 防止java.io.InvalidClassException
    
        //private String testError;
    
        private int userId;
    
        private String userName;
    
        public User(int userId, String userName) {
            this.userId = userId;
            this.userName = userName;
        }
    
        public int getUserId() {
            return userId;
        }
    
        public void setUserId(int userId) {
            this.userId = userId;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    }
    
    

    值得注意的是: private static final long serialVersionUID = 1L;
    建议我们使用 Serializable 接口的时候都手动去指定,虽然是非必须的,但是:如果不指定 serialVersionUID ,User 类序列化后,如果中途增加或减少一个成员变量(比如新增 private String testError; ),这时我们去反序列化将报错:java.io.InvalidClassException

    为什么?序列化的时候系统把当前类的serialVersionUID 写入系列化文件中,当反序列化的时候会去检测文件中的serialVersionUID ,如果一致说明两者版本相同,否则说明两者相比发生了某些变化 ,这时就报错。

     /**
         * 序列化保存 Serializable 数据
         *
         * @param user
         */
        private void saveAsSerializable(User user) {
            Log.d("saveAsSerializable", "User:" + user.getUserName() + " " + user.getUserId());
            FileOutputStream fos;
            ObjectOutputStream oos;
            try {
                fos = getApplicationContext().openFileOutput("cache1.txt",
                        Context.MODE_PRIVATE);
                oos = new ObjectOutputStream(fos);
                oos.writeObject(user);
                oos.close();
                fos.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        /**
         * 反序列化读取 Serializable 数据
         *
         * @return
         */
        private User readSerializable() {
            User obj = null;
            FileInputStream fis;
            ObjectInputStream ois;
            try {
                fis = getApplicationContext().openFileInput("cache1.txt");
                ois = new ObjectInputStream(fis);
                obj = (User) ois.readObject();
                ois.close();
                fis.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            if (obj != null) {
                Log.d("readSerializable", "User:" + obj.getUserName() + " " + obj.getUserId());
                return obj;
            } else {
                return null;
            }
    
        }
    
    
    • Parcelable:
      Android 专用的一个接口,经别人测试,性能比 Serializable 好10倍左右,当在对象持久化储存时不建议使用这个。

    下面是个栗子,其实编译器已经帮忙生成了大部分代码,我们只要写getset 和构造函数就行:

    public class Human implements Parcelable {
        private String address;
        private boolean isMan;
        private Woman woman;
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public boolean isMan() {
            return isMan;
        }
    
        public void setMan(boolean man) {
            isMan = man;
        }
    
        public Woman getWoman() {
            return woman;
        }
    
        public void setWoman(Woman woman) {
            this.woman = woman;
        }
    
        public Human(String address, boolean isMan, Woman woman) {
            this.address = address;
            this.isMan = isMan;
            this.woman = woman;
        }
    
        protected Human(Parcel in) {
            address = in.readString();
            isMan = in.readInt() == 1;
            //反序列化 Woman 属性,由于 Woman 是另一个可序列化对象,所以它的反序列化过程需要传递当前线程的上下文类加载器,否则会报无法找到该类的错误。
            woman = in.readParcelable(Woman.class.getClassLoader());
        }
    
        public static final Creator<Human> CREATOR = new Creator<Human>() {
            @Override
            public Human createFromParcel(Parcel in) {
                return new Human(in);
            }
    
            @Override
            public Human[] newArray(int size) {
                return new Human[size];
            }
        };
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel parcel, int i) {
            parcel.writeString(address);
            parcel.writeInt(isMan ? 1 : 0);
            parcel.writeParcelable(woman, i);
        }
    }
    
    

    这里敲一下黑板:

    1. 需要注意的是 Parcelable 不支持布尔值传输,怎样使用请看上面栗子;

    2. 当我们序列化的类中有其他对象,如例子上的 Woman 类 ,那么这个类也必须实现 Parcelable 接口,同时:反序列化 Woman 属性,由于 Woman 是另一个可序列化对象,所以它的反序列化过程需要传递当前线程的上下文类加载器,否则会报无法找到该类的错误(实现Parcelable 接口生成代码的时候已经自动写了)。(这里得说一下:生成代码前先把所有的成员变量都写了,方便自动生成,不然中途调加变量要相应的补上序列化和反序列化的实现)

    下面是 Parcelable 的序列化与反序列化持久化存储的代码,建议 Intent 传输用 Parcelable 。

     /**
         * 序列化保存 Parcalable 数据
         *
         * @return
         */
        private void saveParce(Human human) {
            Log.d("loadParce", "Human:" + human.getAddress() + " " + human.getWoman().getName());
            FileOutputStream fos;
            try {
                fos = getApplicationContext().openFileOutput("cache2.txt",
                        Context.MODE_PRIVATE);
                BufferedOutputStream bos = new BufferedOutputStream(fos);
                Parcel parcel = Parcel.obtain();
                parcel.writeParcelable(human, 0);
    
                bos.write(parcel.marshall());
                bos.flush();
                bos.close();
                fos.flush();
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 反序列化读取 Parcalable 数据
         *
         * @return
         */
        private void loadParce() {
            FileInputStream fis;
            try {
                fis = getApplicationContext().openFileInput("cache2.txt");
                byte[] bytes = new byte[fis.available()];
                fis.read(bytes);
                Parcel parcel = Parcel.obtain();
                parcel.unmarshall(bytes, 0, bytes.length);
                parcel.setDataPosition(0);
    
                Human data = parcel.readParcelable(Human.class.getClassLoader());
                Log.d("loadParce", "Human:" + data.getAddress() + " " + data.getWoman().getName()+"isMan: "+ data.isMan());
                fis.close();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    

    用 Intent 传输就贼简单了, putExtra 传过去后,采用Serializable 接口的用 getIntent().getSerializableExtra ()、采用 Parcelable 接口的用getIntent().getParcelableExtra() 取出来就行。下面是网上看到的别人使用的代码(采用 Parcelable 接口):

    MainActivity 中

                    Intent mTvOpenThird = new 
                    Intent(MainActivity.this,ThirdActivity.class);
                    Pen tranPen = new Pen();
                    tranPen.setColor("big red");
                    tranPen.setSize(98);
                    // public Intent putExtra(String name, Parcelable value)
                    mTvOpenThird.putExtra("parcel_test",tranPen);
                    startActivity(mTvOpenThird);
    
    
    

    ThirdActivity 中

            Pen pen = (Pen)getIntent().getParcelableExtra("parcel_test");
            mTvThirdDate = (TextView) findViewById(R.id.mTvThirdDate);
            mTvThirdDate.setText("颜色:"+pen.getColor()+"\\n"
                                +"大小:"+pen.getSize());
    
    • 小结一下:Serializable 使用简单但开销较大,序列化和反序列化过程需要大量I/O操作,建议都指定 serialVersionUID ,随便什么数值。所以如果考虑效率的话首选 Parcelable,Parcelable 主要用在内存序列化上,如果将对象持久化保存建议使用 Serializable 。Demo

    相关文章

      网友评论

          本文标题:Android 序列化 - Serializable、Parce

          本文链接:https://www.haomeiwen.com/subject/ekaasftx.html