《Android 开发艺术探索》读书笔记五 IPC机制之Serialzable接口和Parcelable接口

Serialzable和Parcelable接口可以完成对象的序列化过程,当我们需要通过Intent和Binder传输数据时就需要使用Serialzable和Parcelable。

一、Serialzable接口

Serialzable是Java提供的序列化接口,它是一个空接口,为对象提供了标准的序列化和反序列化操作。使用Serialzable来实现序列化非常简单,只需要在类的声明中指定一个类似下面的标识即可自动实现默认的序列化过程,值得注意的是,它有一个serialVersionUID的私有静态成员变量:

private static final long serialVersionUID = 1L;

在序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同时才会正常的被反序列化。

工作机制:序列化的时候系统会当前类的serialVersionUID写入序列化的文件中,当反序列化时系统会去检测文件中的serialVersionUID,是否和当前类的serialVersionUID一致,如果序列化失败,说明当前类和序列化的类相比发生了某些转变,比如成员变量的数据,类型可能发生了改变。会报如下错:

java.io.InvalidClassException:Main; local class incompatible: stream
classdesc serialVersionUID = 8711368828010083044, local class serial
VersionUID = 8711368828010083043.

一般来说,我们应该手动指定serialVersionUID的值,比如1L。
在android源码中Serializable实现如下:

/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package java.io;

/**
 * Marks classes that can be serialized by {@link ObjectOutputStream} and
 * deserialized by {@link ObjectInputStream}.
 *
 * <p><strong>Warning:</strong> this interface limits how its implementing
 * classes can change in the future. By implementing {@code Serializable} you
 * expose your flexible in-memory implementation details as a rigid binary
 * representation. Simple code changes--like renaming private fields--are
 * not safe when the changed class is serializable.
 *
 * <h3>The Serialized Form</h3>
 * By default, the serialization mechanism encodes an object's class name, the
 * names of its non-transient fields (including non-public fields), and the
 * values of all of those fields. The output is an opaque sequence of bytes.
 * Those bytes can be decoded into a new, equivalent instance as long as the
 * decoder has compatible versions of the originating classes.
 *
 * <p>Changing the class name, field names or field types breaks serialization
 * compatibility and complicates interoperability between old and new versions
 * of the serializable class. Adding or removing fields also complicates
 * serialization between versions of a class because it requires your code to
 * cope with missing fields.
 *
 * <p>Every serializable class is assigned a version identifier called a {@code
 * serialVersionUID}. By default, this identifier is computed by hashing the
 * class declaration and its members. This identifier is included in the
 * serialized form so that version conflicts can be detected during
 * deserialization. If the local {@code serialVersionUID} differs from the
 * {@code serialVersionUID} in the serialized data, deserialization will fail
 * with an {@link InvalidClassException}.
 *
 * <p>You can avoid this failure by declaring an explicit {@code
 * serialVersionUID}. Declaring an explicit {@code serialVersionUID} tells the
 * serialization mechanism that the class is forward and backward compatible
 * with all versions that share that {@code serialVersionUID}. Declaring a
 * {@code serialVersionUID} looks like this: <pre>   {@code
 *
 *     private static final long serialVersionUID = 0L;
 * }</pre>
 * If you declare a {@code serialVersionUID}, you should increment it each
 * time your class changes incompatibly with the previous version. Typically
 * this is when you add, change or remove a non-transient field.
 *
 * <p>You can take control of your serialized form by implementing these two
 * methods with these exact signatures in your serializable classes:
 * <pre>   {@code
 *
 *   private void writeObject(java.io.ObjectOutputStream out)
 *       throws IOException {
 *     // write 'this' to 'out'...
 *   }
 *
 *   private void readObject(java.io.ObjectInputStream in)
 *       throws IOException, ClassNotFoundException {
 *     // populate the fields of 'this' from the data in 'in'...
 *   }
 * }</pre>
 * It is impossible to maintain serialization compatibility across a class name
 * change. For this reason, implementing {@code Serializable} in anonymous
 * inner classes is highly discouraged: simply reordering the members in the
 * file could change the generated class name and break serialization
 * compatibility.
 *
 * <p>You can exclude member fields from serialization by giving them the {@code
 * transient} modifier. Upon deserialization, the transient field's value will
 * be null, 0, or false according to its type.
 *
 * <h3>Implement Serializable Judiciously</h3>
 * Refer to <i>Effective Java</i>'s chapter on serialization for thorough
 * coverage of the serialization API. The book explains how to use this
 * interface without harming your application's maintainability.
 *
 * <h3>Recommended Alternatives</h3>
 * <strong>JSON</strong> is concise, human-readable and efficient. Android
 * includes both a {@link android.util.JsonReader streaming API} and a {@link
 * org.json.JSONObject tree API} to read and write JSON. Use a binding library
 * like <a href="http://code.google.com/p/google-gson/">GSON</a> to read and
 * write Java objects directly.
 */
public interface Serializable {
}

二、Parcelable接口

Parcelable接口是Android为我们提供的一种新的序列化方式。我们只需要实现这个接口,就可以实现序列化并通过Intent或Binder进行传递。

系统为我们提供了许多已经实现Parcelable接口的类,它们都是可以直接序列化的,比如:Intent、Bundle、Bitmap等,同时List及Map也可以序列化,前提是它们里面的每个元素都是可序列化的。

其源码如下:

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

/**
 * Interface for classes whose instances can be written to
 * and restored from a {@link Parcel}.  Classes implementing the Parcelable
 * interface must also have a non-null static field called <code>CREATOR</code>
 * of a type that implements the {@link Parcelable.Creator} interface.
 * 
 * <p>A typical implementation of Parcelable is:</p>
 * 
 * <pre>
 * public class MyParcelable implements Parcelable {
 *     private int mData;
 *
 *     public int describeContents() {
 *         return 0;
 *     }
 *
 *     public void writeToParcel(Parcel out, int flags) {
 *         out.writeInt(mData);
 *     }
 *
 *     public static final Parcelable.Creator&lt;MyParcelable&gt; CREATOR
 *             = new Parcelable.Creator&lt;MyParcelable&gt;() {
 *         public MyParcelable createFromParcel(Parcel in) {
 *             return new MyParcelable(in);
 *         }
 *
 *         public MyParcelable[] newArray(int size) {
 *             return new MyParcelable[size];
 *         }
 *     };
 *     
 *     private MyParcelable(Parcel in) {
 *         mData = in.readInt();
 *     }
 * }</pre>
 */
public interface Parcelable {
    /**
     * Flag for use with {@link #writeToParcel}: the object being written
     * is a return value, that is the result of a function such as
     * "<code>Parcelable someFunction()</code>",
     * "<code>void someFunction(out Parcelable)</code>", or
     * "<code>void someFunction(inout Parcelable)</code>".  Some implementations
     * may want to release resources at this point.
     */
    public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;

    /**
     * Bit masks for use with {@link #describeContents}: each bit represents a
     * kind of object considered to have potential special significance when
     * marshalled.
     */
    public static final int CONTENTS_FILE_DESCRIPTOR = 0x0001;

    /**
     * Describe the kinds of special objects contained in this Parcelable's
     * marshalled representation.
     *  
     * @return a bitmask indicating the set of special object types marshalled
     * by the Parcelable.
     */
    public int describeContents();

    /**
     * Flatten this object in to a Parcel.
     * 
     * @param dest The Parcel in which the object should be written.
     * @param flags Additional flags about how the object should be written.
     * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
     */
    public void writeToParcel(Parcel dest, int flags);

    /**
     * Interface that must be implemented and provided as a public CREATOR
     * field that generates instances of your Parcelable class from a Parcel.
     */
    public interface Creator<T> {
        /**
         * Create a new instance of the Parcelable class, instantiating it
         * from the given Parcel whose data had previously been written by
         * {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.
         * 
         * @param source The Parcel to read the object's data from.
         * @return Returns a new instance of the Parcelable class.
         */
        public T createFromParcel(Parcel source);

        /**
         * Create a new array of the Parcelable class.
         * 
         * @param size Size of the array.
         * @return Returns an array of the Parcelable class, with every entry
         * initialized to null.
         */
        public T[] newArray(int size);
    }

    /**
     * Specialization of {@link Creator} that allows you to receive the
     * ClassLoader the object is being created in.
     */
    public interface ClassLoaderCreator<T> extends Creator<T> {
        /**
         * Create a new instance of the Parcelable class, instantiating it
         * from the given Parcel whose data had previously been written by
         * {@link Parcelable#writeToParcel Parcelable.writeToParcel()} and
         * using the given ClassLoader.
         *
         * @param source The Parcel to read the object's data from.
         * @param loader The ClassLoader that this object is being created in.
         * @return Returns a new instance of the Parcelable class.
         */
        public T createFromParcel(Parcel source, ClassLoader loader);
    }
}

Serialzable和Parcelable的区别:

Serialzable和Parcelable都能实现序列化并且都可以用于Intent间的数据传递,但是Serialzable是Java提供的序列化接口,使用起来简单但是开销很大,序列化和反序列化都要进行大量的I/O操作,而Parcelable是Android中的序列化方式,因此更适合Android平台,它的缺点就是使用起来麻烦点,但是效率很高。我们首选Parcelable,Parcelable主要用于内存序列化上,虽然可以实现序列化到存储设备中或通过网络传输,但是这个过程会很麻烦。所以如果是上述两种情况,建议用Serialzable。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值