序列化之Serializable与Parcelable

序列化:把数据结构或者对象转换成二进制串的过程。
反序列化:把二进制串转换成数据结构或者对象的过程。
二进制串:序列化所生成的二进制串指的是存储在内存中的一块数据。二进制串在Java里面所指的是byte[]。

应用场景:数据库,XML等文件存储,套接字,RMI

序列化的作用:

序列化和反序列化的过程是为了方便以本地文件、数据库、网络流、RMI等方式传输数据。
如果没有序列化的存在,例如:要利用XML等文件存储对象中的数据时,我们就需要手动把对象中的数据逐个存入文件中。传输完成后再从文件中逐个取出数据在转换成对象。(序列化反序列化其实就是这个过程,只是把该功能封装起来了)

在操作数据库时,有时候我们并不会实现序列化也可以保存到数据库中,如:

public class Car{
    private int price;
    private String color;
    public static String model;
    transient String user;
}

数据库中保存了对应的表字段,插入数据库的时候,只需要把car对象的变量值保存到相应的表字段就可以了。
这是否说明了数据库的场景下不需要序列化?
查看资料后,比较好的解释是:Sql中的数据结构恰好能对应java的基础数据类型,因此不用序列化也可以直接保存。另外一种数据库Nosql是没有定义数据结构的,因此在保存到此类数据库时,还是需要实现序列化的。(硬盘也是没有相应的数据结构的)

序列化的实现:

  • java提供了Serializable接口
  • android提供了Parcelable接口

Serializable接口

Serializable接口没有定义任何方法或字段,仅用于识别可序列化的语义。
java集合多数实现了Serializable接口,比如ArrayList,HashSet,HashMap等等。

Serializable的使用注意事项:

  • 实现Serializable需要使用IO流对文件进行读写操作
  • static 修饰的变量不参与序列化
  • transient 修饰的变量也不参与序列化,反序列化后该变量变为默认值
  • 序列化过程中,如果在Serializable实现类中,使用了非Serializable实现类的对象,则该对象在反序列化时,里面所有的变量均变为默认值(不参与序列化)
  • 子类实现了Serializable,而父类没有实现Serializable。父类必须要有无参构造函数。
  • Serializable的实现类均有一个private static final long serialVersionUID
    变量,如果没有显示定义,在序列化的时候jvm会给我们默认定义,默认定义的serialVersionUID
    会跟随实现类实体的修改而动态变化,这个需要注意。这个serialVersionUID
    是用来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即InvalidCastException。如果需要自定义serialVersionUID
    ,可以参照ObjectStreamClass.java,这个源码中有对serialVersionUID
    进行自定义。另外,我们可以通过ObjectStreamClass类来获取serialVersionUID 。参见例子。

序列化到文件存储中的例子:

public class Car extends ProductionBase implements Serializable{

    private int price;
    private String color;
    static String model = "Lamborghini";
    transient String user;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "Car{" +
                "price=" + price +
                ", color='" + color + '\'' +
                ", model='" + model + '\'' +
                ", user='" + user + '\'' +
                ", " + super.toString() + '\'' +
                '}';
    }
}

public class ProductionBase {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "ProductionBase{" +
                "address='" + address + '\'' +
                '}';
    }
}

public class SerializableTest {

    private static String path = "F:\\AndroidStudioProjects\\Android_Example\\java_example\\src\\main\\java\\com\\example\\serializable\\SerializableCar.txt";
    public static void main(String args[]){

        Car myCar = new Car();
        myCar.setColor("while");
        myCar.setPrice(9999999);
        myCar.setUser("my wife");
        myCar.setAddress("China");
        try {
            System.out.println("myCar is :" + myCar.toString());
            SerializableCar(myCar);//序列化
            Car.model = "Ferrari";
            myCar.setColor("black");
            myCar.setPrice(8888888);
            myCar.setUser("myself");
            myCar.setAddress("Japan");

            Object object = DeserializationCar(path);//反序列化
            Car newCar = (Car)object;

            System.out.println("newCar is :" + newCar.toString());
            //获取默认的SerialVersionUID值
            ObjectStreamClass osc2 = ObjectStreamClass.lookup(Car.class);
            System.out.println("SerialVersionUID :" + osc2.getSerialVersionUID());

        }catch (Exception e){
            e.printStackTrace();
        }
    }
    //序列化
    public static void SerializableCar(Object object) throws IOException {
        File mFile = new File(path);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(mFile));
        oos.writeObject(object);
        oos.close();
        System.out.println("SerializableCar is success, Serializable file is in "+ path);
    }
    //反序列化
    public static Object DeserializationCar(String mPath) throws  IOException,ClassNotFoundException{
        File mFile = new File(mPath);
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(mFile));
        Object object = ois.readObject();
        System.out.println("DeserializationCar is success, return the Object");
        return object;
    }
}

打印输出:

myCar is :Car{price=9999999, color='while', model='Lamborghini', user='my wife', ProductionBase{address='China'}'}
SerializableCar is success, Serializable file is in F:\AndroidStudioProjects\Android_Example\java_example\src\main\java\com\example\serializable\SerializableCar.txt
DeserializationCar is success, return the Object
newCar is :Car{price=9999999, color='while', model='Ferrari', user='null', ProductionBase{address='null'}'}
SerialVersionUID :5568593075854263741

以上的例子中,在执行序列化之后再修改对象的值,通过查看log打印的差异之处,可以看到变量是否被序列化。


Parcelable接口

鉴于移动设备的内存资源比较稀缺,Android设计了Parcelable序列化的方式,Parcelable和Serializable之间的差别有:
Serializable序列化

  • 通过本地文件、数据库、网络流、RMI等方式进行数据的传输。
  • 使用外部存储器进行数据的读写操作,效率低。
  • 除了transient和static修饰的变量,类中所有的变量都会实现序列化。
  • 使用起来比较简单。

Parcelable序列化

  • 一般只能以内存的方式进行数据的传输。
  • 直接在内存中对数据进行读写,效率高。
  • 可以自定义需要序列化的变量,自定义反序列化的变量。
  • 使用起来比较繁琐。

一. Parcelable的使用

在Parcelable接口的注释中,官方已经规定好该怎么样去使用Parcelable了,如下:

 * <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>

总结起来有四点:
1. 必须实现writeToParcel()方法,把数据封装到Parcel中,Parcel帮我们实现了序列化功能(类似于Serializable输出流)
2. 必须实现一个public static final类型的CREATOR变量,并实现createFromParcel()方法和newArray()方法。既然Parcel帮我们实现了序列化的功能,那么它也帮我们实现了反序列化的功能,我们需要从createFromParcel()方法中获取Parcel对象以获取反序列化后的数据。
3. 从Parcel中获取反序列化后的数据。这一步可以在Parcelable子类的构造方法中执行也可以在createFromParcel()中执行。
4. 实现describeContents()方法,这个方法默认返回0。暂不知具体作用。

实现了Parcelable之后,就可以正常使用Parcelable进行序列化反序列化的操作了。但是它并不像Serializable的使用方式一样,需要自己直接调用writeToParcel()和createFromParcel()去实现,这些调用全部被封装起来了,Parcelable一般是建议使用在Intent意图跳转的时候传输数据,比如:

xxxx

Intent mIntent = new Intent(getApplicationContext(), xxxx.class);
Bundle mBundle = new Bundle();
mBundle.putParcelable("xxxx", Parcelable实现类对象);
mIntent.putExtras(mBundle);
startActivity(mIntent);

xxxxx

Intent mIntent = getIntent();
Parcelable xx= mIntent.getParcelableExtra("xxxx");

具体的例子如下:

public class Car extends ProductionBase implements Parcelable {

    public int price;
    public String color;
    public static String model;
    public transient String user;

    public Car(Parcel in){
        price = in.readInt();
        color = in.readString();
        model = in.readString();
        user = in.readString();
    }

    public static final Creator<Car> CREATOR = new Creator<Car>(){

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

        @Override
        public Car createFromParcel(Parcel source) {
            Log.d("MainActivity", "createFromParcel :" + source.toString()+ Log.getStackTraceString(new Throwable()));
            return new Car(source);
        }
    };
    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(price);
        dest.writeString(color);
        dest.writeString(model);
        dest.writeString(user);
        Log.d("MainActivity", "writeToParcel:" + source.toString()+ Log.getStackTraceString(new Throwable()));
    }
}
public class ProductionBase {
    private String address;
}
public class MainActivity extends AppCompatActivity {
    public static String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Parcel mParcel = Parcel.obtain();
        final Car mCar = new Car(mParcel);
        Car.model = "Lamborghini";
        mCar.setColor("while");
        mCar.setPrice(9999999);
        mCar.setUser("my wife");
        mCar.setAddress("China");
        Log.d(TAG, "new Car :" + mCar.toString());
        Button button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent mIntent = new Intent(getApplicationContext(), Main2Activity.class);
                Bundle mBundle = new Bundle();
                mBundle.putParcelable("mydata", mCar);
                mIntent.putExtras(mBundle);

                Log.d(TAG, "OnClickListener :" + mIntent.getExtras().getParcelable("mydata").toString());
                startActivity(mIntent);
            }
        });

    }
}
public class Main2Activity extends AppCompatActivity {

    private String TAG = "Main2Activity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        try {
            Intent mIntent = getIntent();
            Car mCar = mIntent.getParcelableExtra("mydata");
            Log.d(TAG, "get Car from intent :" + mCar.toString());

        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

二. writeToParcel()和createFromParcel()源码分析

以上的例子中,并没有看到writeToParcel()和createFromParcel()被显示的调用。其实那只是被封装起来了而已。如下:
首先,Intent和Bundle都是Parcelable的实现类,如果我们把Parcelable 实现类对象再保存到Intent和Bundle中,就相当于是Parcelable 的嵌套使用了。
Intent内部维护了一个Bundle对象,用来保存所有Intent中的数据。Intent中取出数据也是来自Bundle。而Bundle内部则是使用了Map键值对的形式来保存数据。
Intent.java

public Intent putExtra(String name, Parcelable value) {
    if (mExtras == null) {
        mExtras = new Bundle();
    }
    mExtras.putParcelable(name, value);
    return this;
}
public <T extends Parcelable> T getParcelableExtra(String name) {
    return mExtras == null ? null : mExtras.<T>getParcelable(name);
}

Bundle.java

ArrayMap<String, Object> mMap = null;
public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
    unparcel();
    mMap.put(key, value);
    mFdsKnown = false;
}
public <T extends Parcelable> T getParcelable(@Nullable String key) {
    unparcel();
    Object o = mMap.get(key);
    if (o == null) {
        return null;
    }
    try {
        return (T) o;
    } catch (ClassCastException e) {
        typeWarning(key, o, "Parcelable", e);
        return null;
    }
}

例子中,我们在writeToParcel()和createFromParcel()方法中打印了调用栈:
writeToParcel():
这里写图片描述
createFromParcel():
这里写图片描述
根据调用栈的流程,我们从ActivityManagerProxy.java的startActivity()开始研究源码:

ActivityManagerProxy.java

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
        String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeString(callingPackage);
    //获取Parcel对象,把Intent中的信息保存到Parcel对象中。之后就是Parcel实现序列化的过程。
    intent.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeStrongBinder(resultTo);
    data.writeString(resultWho);
    data.writeInt(requestCode);
    data.writeInt(startFlags);
    if (profilerInfo != null) {
        data.writeInt(1);
        profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    } else {
        data.writeInt(0);
    }
    if (options != null) {
        data.writeInt(1);
        options.writeToParcel(data, 0);
    } else {
        data.writeInt(0);
    }
    //Intent意图跳转,无论是否是跨进程通讯,都执行此方法。
    mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
    reply.readException();
    int result = reply.readInt();
    reply.recycle();//序列化反序列化结束后,需要释放Parcel对象通过JNI调用C++代码申请的内存空间
    data.recycle();
    return result;
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
    switch (code) {
    case START_ACTIVITY_TRANSACTION:
    {
        data.enforceInterface(IActivityManager.descriptor);
        IBinder b = data.readStrongBinder();
        IApplicationThread app = ApplicationThreadNative.asInterface(b);
        String callingPackage = data.readString();
        Intent intent = Intent.CREATOR.createFromParcel(data);//反序列化获取Intent信息。(new Intent)
        String resolvedType = data.readString();
        IBinder resultTo = data.readStrongBinder();
        String resultWho = data.readString();
        int requestCode = data.readInt();
        int startFlags = data.readInt();
        ProfilerInfo profilerInfo = data.readInt() != 0
                ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
        //如果startActivity()时传入了Bundle参数,反序列化获取Bundle信息(new BundleBundle options = data.readInt() != 0
                ? Bundle.CREATOR.createFromParcel(data) : null;
        //调用了AMS中的startActivity(),根据反序列得到的Intent信息,启动Activity
        int result = startActivity(app, callingPackage, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
        reply.writeNoException();
        reply.writeInt(result);
        return true;
    }
    ......
}

Intent.java

//把Intent中的Bundle对象引用传递到Parcel对象中
public void writeToParcel(Parcel out, int flags) {
    out.writeString(mAction);
    Uri.writeToParcel(out, mData);
    out.writeString(mType);
    out.writeInt(mFlags);
    out.writeString(mPackage);
    ComponentName.writeToParcel(mComponent, out);

    if (mSourceBounds != null) {
        out.writeInt(1);
        mSourceBounds.writeToParcel(out, flags);
    } else {
        out.writeInt(0);
    }

    if (mCategories != null) {
        final int N = mCategories.size();
        out.writeInt(N);
        for (int i=0; i<N; i++) {
            out.writeString(mCategories.valueAt(i));
        }
    } else {
        out.writeInt(0);
    }

    if (mSelector != null) {
        out.writeInt(1);
        mSelector.writeToParcel(out, flags);
    } else {
        out.writeInt(0);
    }

    if (mClipData != null) {
        out.writeInt(1);
        mClipData.writeToParcel(out, flags);
    } else {
        out.writeInt(0);
    }
    out.writeInt(mContentUserHint);
    out.writeBundle(mExtras);//把Intent中的Bundle对象引用传递到Parcel对象中
}

Parcel.java

    public final void writeBundle(Bundle val) {
        if (val == null) {
            writeInt(-1);
            return;
        }

        val.writeToParcel(this, 0);
    }
    //循环ArrayMap集合,把集合中的数据通过Parcel写入到内存
    /* package */ void writeArrayMapInternal(ArrayMap<String, Object> val) {
        if (val == null) {
            writeInt(-1);
            return;
        }
        final int N = val.size();
        writeInt(N);
        if (DEBUG_ARRAY_MAP) {
            RuntimeException here =  new RuntimeException("here");
            here.fillInStackTrace();
            Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
        }
        int startPos;
        for (int i=0; i<N; i++) { //循环map集合,把map中的数据写入到内存
            if (DEBUG_ARRAY_MAP) startPos = dataPosition();
            writeString(val.keyAt(i));
            writeValue(val.valueAt(i));
            if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Write #" + i + " "
                    + (dataPosition()-startPos) + " bytes: key=0x"
                    + Integer.toHexString(val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0)
                    + " " + val.keyAt(i));
        }
    }    
//根据键值对中value的类型匹配对应的处理方法
public final void writeValue(Object v) {
    if (v == null) {
        writeInt(VAL_NULL);
    } else if (v instanceof String) {
        writeInt(VAL_STRING);
        writeString((String) v);
    } else if (v instanceof Integer) {
        writeInt(VAL_INTEGER);
        writeInt((Integer) v);
    } else if (v instanceof Map) {
        writeInt(VAL_MAP);
        writeMap((Map) v);
    } else if (v instanceof Bundle) {
        // Must be before Parcelable
        writeInt(VAL_BUNDLE);
        writeBundle((Bundle) v);
    } else if (v instanceof Parcelable) {
        writeInt(VAL_PARCELABLE);
        writeParcelable((Parcelable) v, 0);
    } 
    ......
}    
//调用Parcelable实现类中的writeToParcel()方法,把数据写入内存
public final void writeParcelable(Parcelable p, int parcelableFlags) {
    if (p == null) {
        writeString(null);
        return;
    }
    writeParcelableCreator(p);
    p.writeToParcel(this, parcelableFlags);
}
//在数据写入内存之前,把Parcelable实现类的类名也写入到内存
public final void writeParcelableCreator(Parcelable p) {
    String name = p.getClass().getName();
    writeString(name);
}
//Parcel读取内存数据,然后把数据保存到一个新的ArrayMap集合中
/* package */ void readArrayMapInternal(ArrayMap outVal, int N,
    ClassLoader loader) {
    if (DEBUG_ARRAY_MAP) {
        RuntimeException here =  new RuntimeException("here");
        here.fillInStackTrace();
        Log.d(TAG, "Reading " + N + " ArrayMap entries", here);
    }
    int startPos;
    while (N > 0) {
        if (DEBUG_ARRAY_MAP) startPos = dataPosition();
        String key = readString();
        Object value = readValue(loader);//读取内存数据
        if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Read #" + (N-1) + " "
                + (dataPosition()-startPos) + " bytes: key=0x"
                + Integer.toHexString((key != null ? key.hashCode() : 0)) + " " + key);
        outVal.append(key, value);
        N--;
    }
    outVal.validate();
}
//调用Parcelable实现类中的匿名内部类Creator中的createFromParcel()方法
public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
    Parcelable.Creator<?> creator = readParcelableCreator(loader);
    if (creator == null) {
        return null;
    }
    if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
      Parcelable.ClassLoaderCreator<?> classLoaderCreator =
          (Parcelable.ClassLoaderCreator<?>) creator;
      return (T) classLoaderCreator.createFromParcel(this, loader);
    }
    return (T) creator.createFromParcel(this);
}

Bundle.java & BaseBundle.java

//调用父类的writeToParcelInner()方法处理Parcel
public void writeToParcel(Parcel parcel, int flags) {
    final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
    try {
        super.writeToParcelInner(parcel, flags);
    } finally {
        parcel.restoreAllowFds(oldAllowFds);
    }
}
//把Bundle中的map集合中的数据通过parcel对象写入内存,并设置parcel对象的相关参数。
void writeToParcelInner(Parcel parcel, int flags) {
    if (mParcelledData != null) {
        if (mParcelledData == EMPTY_PARCEL) {
            parcel.writeInt(0);
        } else {
            int length = mParcelledData.dataSize();
            parcel.writeInt(length);
            parcel.writeInt(BUNDLE_MAGIC);
            parcel.appendFrom(mParcelledData, 0, length);
        }
    } else {
        // Special case for empty bundles.
        if (mMap == null || mMap.size() <= 0) {
            parcel.writeInt(0);
            return;
        }
        int lengthPos = parcel.dataPosition();
        parcel.writeInt(-1); // dummy, will hold length
        parcel.writeInt(BUNDLE_MAGIC);

        int startPos = parcel.dataPosition();
        parcel.writeArrayMapInternal(mMap);//把Bundle中的map对象保存到parcel对象中
        int endPos = parcel.dataPosition();

        // Backpatch length
        parcel.setDataPosition(lengthPos);
        int length = endPos - startPos;
        parcel.writeInt(length);
        parcel.setDataPosition(endPos);
    }
}
//通过parcel读取内存数据,并把这些数据保存到bundle的map集合中
/* package */ synchronized void unparcel() {
    if (mParcelledData == null) {
        if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
                + ": no parcelled data");
        return;
    }

    if (mParcelledData == EMPTY_PARCEL) {
        if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
                + ": empty");
        if (mMap == null) {
            mMap = new ArrayMap<String, Object>(1);
        } else {
            mMap.erase();
        }
        mParcelledData = null;
        return;
    }

    int N = mParcelledData.readInt();
    if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
            + ": reading " + N + " maps");
    if (N < 0) {
        return;
    }
    if (mMap == null) {
        mMap = new ArrayMap<String, Object>(N);
    } else {
        mMap.erase();
        mMap.ensureCapacity(N);
    }
    mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
    mParcelledData.recycle();
    mParcelledData = null;
    if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
            + " final map: " + mMap);
}

总结以上源码:

  • 执行putExtra()把Parcelable对象加入到Intent中,实际上就是创建了Bundle对象,把Parcelable对象保存到了Bundle对象的map集合中。执行startActivity()的过程中,ActivityManagerProxy会获取一个Parcel对象,并把Intent中携带的Bundle对象引用传递给Parcel对象,Parcel通过Bundle对象的引用访问map集合,把map集合中的Parcelable类型的数据写入内存。序列化结束。(Intent也是Parcelable类型,它同样序列化了)
  • 在startActivity()中,序列化结束后,接着执行onTransact()方法,马上借助Parcel对象反序列化了Intent和Bundle。AMS根据Intent信息启动了Activity,接着释放了Parcel对象所占有的内存空间(C++)。
  • 当我们调用getIntent().getParcelableExtra(String key)时,会先调用Bundle中的unparcel()方法通过Parcel对象读取内存中的数据,然后保存到Bundle的Map集合(空集合)中,之后通过key返回map中的value值。反序列化结束。

三. Parcel源码分析

Parcelable的序列化和反序列化功能,都封装在了Parcel中,那么Parcel是如何实现在内存中进行序列化和反序列化呢?我们先来看看Parcel中代码的部分实现:

  1. Parcel 内部维护了两个6位的数组sOwnedPool ,sHolderPool 当做缓冲池。sOwnedPool 中保存的是nativePtr = 0的Parcel 对象。sHolderPool 中保存的是nativePtr != 0的Parcel 对象。由于Parcel 的构造函数是private,因此提供了两个obtain()方法,一个不带参数,一个带int参数(nativePtr 值)。
  2. nativePtr值是什么,通过JNI的调用关系查看c++代码,发现nativePtr 其实就是一个内存地址的Long类型表示。c代码中把指向内存的指针转换成Long类型的数值。
  3. Parcel 中对数据的序列化和反序列化是通过JNI调用c++代码来实现的。c代码中的指针可以直接操作内存。

Parcel:

private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
private static final int POOL_SIZE = 6;
//获取sOwnedPool 缓冲池中的Parcel对象
public static Parcel obtain() {
    final Parcel[] pool = sOwnedPool;
    synchronized (pool) {
        Parcel p;
        for (int i=0; i<POOL_SIZE; i++) {
            p = pool[i];
            if (p != null) {
                pool[i] = null;
                if (DEBUG_RECYCLE) {
                    p.mStack = new RuntimeException();
                }
                return p;
            }
        }
    }
    return new Parcel(0);
}
/*获取sHolderPool缓冲池中的Parcel对象。由于obtain()是protected修饰的且Parcel类定义为final,
*所以此方法只能被子类方法调用,但是Parcel并没有子类。
*/
static protected final Parcel obtain(long obj) {
    final Parcel[] pool = sHolderPool;
    synchronized (pool) {
        Parcel p;
        for (int i=0; i<POOL_SIZE; i++) {
            p = pool[i];
            if (p != null) {
                pool[i] = null;
                if (DEBUG_RECYCLE) {
                    p.mStack = new RuntimeException();
                }
                p.init(obj);
                return p;
            }
        }
    }
    return new Parcel(obj);
}

private Parcel(long nativePtr) {
    if (DEBUG_RECYCLE) {
        mStack = new RuntimeException();
    }
    //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);
    init(nativePtr);
}
/*如果指定了nativePtr,说明此Parcel对象中的数据已经写入过内存,并且没有被释放掉,
*把nativePtr赋值给*mNativePtr,并把mOwnsNativeParcelObject设置为false(此Parcel对象
*在缓冲池未满的情况下会加入到sHolderPool缓冲池)。如果没有指定nativePtr,说明此
*Parcel对象中的数据没有写入过内存,通过JNI调用与nativeCreate()相映射的方法。把数据
*写入到内存中并返回此数据在内存中的地址赋值给mNativePtr(Long类型),mOwnsNativeParcelObject 
*设置为true,此Parcel对象在缓冲池未满的情况下会加入到sOwnedPool缓冲池)
*/
private void init(long nativePtr) {
    if (nativePtr != 0) {
        mNativePtr = nativePtr;
        mOwnsNativeParcelObject = false;
    } else {
        mNativePtr = nativeCreate();
        mOwnsNativeParcelObject = true;
    }
}
/*如果当前Parcel对象不再被使用,此方法执行。会调用freeBuffer()释放掉当前Parcel对象
*所指向的mNativePtr数值的内存,并根据mOwnsNativeParcelObject值判断当前Parcel对象
*是保存到sOwnedPool缓冲池中还是sHolderPool缓冲池中。如果缓冲池已满,则不再加入。
*/
public final void recycle() {
    if (DEBUG_RECYCLE) mStack = null;
    freeBuffer();

    final Parcel[] pool;
    if (mOwnsNativeParcelObject) {
        pool = sOwnedPool;
    } else {
        mNativePtr = 0;
        pool = sHolderPool;
    }

    synchronized (pool) {
        for (int i=0; i<POOL_SIZE; i++) {
            if (pool[i] == null) {
                pool[i] = this;
                return;
            }
        }
    }
}
//通过JNI调用c++代码中与nativeFreeBuffer()相映射的方法,释放内存
private void freeBuffer() {
    if (mOwnsNativeParcelObject) {
        nativeFreeBuffer(mNativePtr);
    }
}
//通过JNI调用c++代码与nativeReadInt()相映射的方法,读取内存中的数据
public final int readInt() {
    return nativeReadInt(mNativePtr);
}
//通过JNI调用c++代码与nativeReadString()相映射的方法,读取内存中的数据
public final String readString() {
    return nativeReadString(mNativePtr);
}

public final void writeString(String val) {
    mReadWriteHelper.writeString(this, val);
}
//通过JNI调用c++代码与writeString()相映射的方法,把数据写入内存
public void writeString(Parcel p, String s) {
    nativeWriteString(p.mNativePtr, s);
}

Frameworks/base/core/jni/android_os_Parcel.cpp
这里面有一个函数映射表,映射了java中的方法和c中的方法:

{"nativeCreate",              "()J", (void*)android_os_Parcel_create},
{"nativeReadString",          "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString},
{"nativeWriteString",         "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
{"nativeFreeBuffer",          "(J)J", (void*)android_os_Parcel_freeBuffer},
{"nativeReadInt",             "(J)I", (void*)android_os_Parcel_readInt},

//c++代码中也定义了相关的Parcel类,新建一个Parcel对象,并把此对象的指针转换成Long类型并返回。
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
    //Frameworks/native/libs/binder/include/binder/Parcel.h
    //Frameworks/native/libs/binder/Parcel.cpp
    Parcel* parcel = new Parcel();
    return reinterpret_cast<jlong>(parcel);
}
//释放相关Parcel对象指针所指向的内存空间
static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        parcel->freeData();
        return parcel->getOpenAshmemSize();
    }
    return 0;
}
//读取Parcel对象指针所指向的内存数据
static jint android_os_Parcel_readInt(jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return parcel->readInt32();
    }
    return 0;
}
//读取Parcel对象指针所指向的内存数据
static jstring android_os_Parcel_readString(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        size_t len;
        const char16_t* str = parcel->readString16Inplace(&len);
        if (str) {
            return env->NewString(reinterpret_cast<const jchar*>(str), len);
        }
        return NULL;
    }
    return NULL;
}
//在Parcel对象指针所指向的内存中写入数据
static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        status_t err = NO_MEMORY;
        if (val) {
            const jchar* str = env->GetStringCritical(val, 0);
            if (str) {
                err = parcel->writeString16(
                    reinterpret_cast<const char16_t*>(str),
                    env->GetStringLength(val));
                env->ReleaseStringCritical(val, str);
            }
        } else {
            err = parcel->writeString16(NULL, 0);
        }
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

Frameworks/native/libs/binder/Parcel.cpp

status_t Parcel::writeString16(const String16& str)
{
    return writeString16(str.string(), str.size());
}

status_t Parcel::writeString16(const char16_t* str, size_t len)
{
    if (str == NULL) return writeInt32(-1);

    status_t err = writeInt32(len);
    if (err == NO_ERROR) {
        len *= sizeof(char16_t);
        uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
        if (data) {
            memcpy(data, str, len); //内存操作
            *reinterpret_cast<char16_t*>(data+len) = 0;
            return NO_ERROR;
        }
        err = mError;
    }
    return err;
}

总结以上源码:

java层从Parcel缓冲池中获取Parcel对象,如果Parcel对象的mNativePtr = 0,JNI映射C++代码,也创建C++中的Parcel对象,并为C++中的Parcel对象分配内存空间,把Parcel对象的指针返回给java层的Parcel对象中的mNativePtr。java层的Parcel对象执行writer操作,JNI映射到C++代码,C++层的Parcel对象操作指针对内存进行writer操作。read操作和freeBuffer操作同理。


附:

BaseBundle.java中mParcelledData变量的赋值:

Intent携带Bundle对象进行意图跳转时开始,保存的是ActivityManagerProxy获取的Parcel对象:
startActivity() -> onTransact() -> Intent.CREATOR.createFromParcel(data) ->new Intent(in) ->readFromParcel(in) ->in.readBundle() ->new Bundle(this, length) ->super(parcelledData, length) ->readFromParcelInner(parcelledData, length)

    private void readFromParcelInner(Parcel parcel, int length) {
        if (length == 0) {
            // Empty Bundle or end of data.
            mParcelledData = EMPTY_PARCEL;
            return;
        }
        int magic = parcel.readInt();
        if (magic != BUNDLE_MAGIC) {
            //noinspection ThrowableInstanceNeverThrown
            throw new IllegalStateException("Bad magic number for Bundle: 0x"
                    + Integer.toHexString(magic));
        }

        // Advance within this Parcel
        int offset = parcel.dataPosition();
        parcel.setDataPosition(offset + length);

        Parcel p = Parcel.obtain();
        p.setDataPosition(0);
        p.appendFrom(parcel, offset, length);
        if (DEBUG) Log.d(TAG, "Retrieving "  + Integer.toHexString(System.identityHashCode(this))
                + ": " + length + " bundle bytes starting at " + offset);
        p.setDataPosition(0);

        mParcelledData = p;
    }
}

疑问:

  1. 如果不使用Intent意图跳转来使用Parcelable,如何手动序列化和反序列化?

    以下获取的newCar为null

    Parcel mParcel = Parcel.obtain();
    final Car mCar = new Car(mParcel);
    Car.model = "Lamborghini";
    mCar.setColor("while");
    mCar.setPrice(9999999);
    mCar.setUser("my wife");
    mCar.setAddress("China");
    //序列化
    mCar.writeToParcel(mParcel, 0);
    Car newCar =mParcel.readParcelable(null);
    Log.d(TAG, "readParcelable :" + newCar.toString());
  2. static 和 transient 修饰的变量是否参与Parcelable序列化?

  3. Parcel与Binder的关系?

参考:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0204/2410.html
https://blog.csdn.net/chzphoenix/article/details/79799289
http://www.droidsec.cn/%E5%BD%BB%E5%BA%95%E7%90%86%E8%A7%A3android-binder%E9%80%9A%E4%BF%A1%E6%9E%B6%E6%9E%84/
https://blog.csdn.net/caowenbin/article/details/6532217
https://blog.csdn.net/rainbowchou/article/details/54294394

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值