Parcelable解读

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class Data implements Parcelable {

    /**
     * 字段
     */
    private String name;

    /**
     * 构造方法内读取
     * @param in
     */
    protected Data(Parcel in) {
        name = in.readString();
    }

    /**
     * 写入
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
    }

    /**
     * 生成器常量
     */
    public static final Creator<Data> CREATOR = new Creator<Data>() {

        /**
         * 调用构造方法生成一个实例
         * @param in
         * @return
         */
        @Override
        public Data createFromParcel(Parcel in) {
            return new Data(in);
        }

        /**
         * 生成对应类型的数组
         * @param size
         * @return
         */
        @Override
        public Data[] newArray(int size) {
            return new Data[size];
        }
    };

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



    //===========以下是getter和setter访问器

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Parcelable使用:

  1. 继承Parcelable接口;
  2. 声明构造方法,从Parcel中序列化数据;
  3. 重写writeToParcel(Parcel dest, int flags)方法,用来反序列化;
  4. 创建Creator<Data>类型的CREATOR,其内部实现了反序列化对象和数组的方法;
  5. 重写describeContents()方法。

Parcel

我们知道,序列化和反序列化都离不开Parcel对象,那他是个啥?

序列化的调用顺序:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//在我们的自定义类中:
@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(name);
}

//最终调用Parcel类中:
public void writeString16NoHelper(@Nullable String val) {
    nativeWriteString16(mNativePtr, val);
}

//本地JNI方法
@FastNative
private static native void nativeWriteString16(long nativePtr, String val);

Parcel用来包装数据,并且提供了大量的read/write方法,最终会调用本地方法通过Binder读写数据到一块共享内存

这里就与Serializable有很大的不同。Serializable的原理是通过IO将数据写到一个文件中

那么而这对比,肯定内存的读写性能要高于硬盘文件系统啊,这就是为什么Parcelable比Serializable快很多的原因。

Parcel的创建

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//池子内最大6个
private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parce[POOL_SIZE];

@NonNull
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;
                //重置属性
                p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
                //返回
                return p;
            }
        }
    }
    //如果池子是空的则new一个
    return new Parcel(0);
}

Parcel的回收

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
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;
            }
        }
    }
}

啥意思呢?本来这个Parcel是自由的,有个民警同志带着这个parcel去看守所转了一圈,一旦发现有空牢房,就把Parcel扔进去,就算回收了。等刑满社会需要Parcel的时候再放出来给社会做贡献。

Parcel的销毁

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Override
protected void finalize() throws Throwable {
    if (DEBUG_RECYCLE) {
        if (mStack != null) {
            Log.w(TAG, "Client did not call Parcel.recycle()", mStack);
        }
    }
    destroy();
}

private void destroy() {
    resetSqaushingState();
    if (mNativePtr != 0) {
        if (mOwnsNativeParcelObject) {
            nativeDestroy(mNativePtr);
            updateNativeSize(0);
        }
        mNativePtr = 0;
    }
}

竟然是重写finalize()方法手动销毁的!

finalize()方法会在GC时回调,用来释放非Java对象,比如JNI中的C/C++对象。此处是为了调用nativeDestroy(mNativePtr)方法释放本地C++对象。