進程
進程有自己的內存地址, 一個進程中的1000地址可能在另一個進程中是10000, java的引用本質上還是內存地址, 如果要傳遞一個類的實例, 還需要傳遞方法等等, 方法是獨立與類對象存在的, 所以到另一個進程中去引用同一個方法就錯了, 還是因為獨立內存地址的原因.
Android中Activity之間并不能保證兩個Activity在同一個進程中, 比如一個APP調用系統(tǒng)打電話功能, 就是兩個進程, 所以需要進程間通信
序列化
- 序列化一個實例對象編碼成字節(jié)流, 存入物理內存/用于傳輸
- 反序列化從字節(jié)流對象中再次重新構建對象實例。
和JSON XML不同的是 JSON XML 是字符描述型對象, 它們是通用的, 不依賴于任何語言平臺
SerializableLink
JVM 虛擬機中的對象, 其內部的狀態(tài)只存在于內存中, JVM 停止后這些數(shù)據(jù)就丟失了, 所以考慮到持久化 , 通常是保存在文件系統(tǒng)或者數(shù)據(jù)庫中, 比如 對象映射關系(Object-relational mapping), 對象序列化機制(Object serialization)是Java提供的一種對象持久化方式, 將JVM中的對象和字節(jié)數(shù)組流之間進行轉換
過程簡述: Java 的 ObjectOutputStream 類用來持久化一個對象, 通過 writeObject 方法把這個類的對象寫到一個文件, 再通過 ObjectInputStream 的readObject 方法把這個對象讀出來.
- 具備 serialVersionUID, 用來標識當前序列化對象的版本, 如果需要本地存儲, 建議每一個實現(xiàn) Serializable 的類都指定 serialVersionUID. 如果沒有指定, JVM 會根據(jù)類的信息自動生成一個 UID, 我們可以通過 JDK 的 serialver 命令來查看一個 .class 的 UID
- 被
transient
描述的域和類的靜態(tài)變量不會被序列化 (static修飾的變量會改變, 但那是因為它放在靜態(tài)區(qū), 而不是因為序列化)Link - transient 只能描述變量, 不能描述類和方法(局部變量無法被修飾--類的方法中定義的變量)
- 如果一個實現(xiàn)了Serializable的類繼承自另一個類, 那么這個類必須實現(xiàn)Serializable或者提供一個無參構造函數(shù)
- 反序列化并不是通過構造器創(chuàng)建的,
- 因為序列化的過程是可見的, 所以EffectiveJava的作者在第77節(jié)中希望使用靜態(tài)內部類防止被攻擊
過程
- 序列化
- 是否替換即將寫入流的對象, writeReplace, 比如使用靜態(tài)內部類代理
- 將對象寫成流, writeObject,
- ObjectOutputStream.defaultWriteObject()默認的序列化過程
- 反序列化
- 將流讀成對象, readObject
- 如果序列化時自定義了序列化過程, 這里也需要自定義反序列化過程
- 是否替換從流中讀出來的對象, readResolve
- 將流讀成對象, readObject
- 示例bean
import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.Serializable; class Persion implements Serializable { public String desc; public String name; public Persion(String desc, String name) { this.desc = desc; this.name = name; } static class SerializableProxy implements Serializable{ private String desc; private String name; private SerializableProxy(Persion s) { this.desc = s.desc; this.name = s.name; } /** * 在這里恢復外圍類 * 注意看這里!!!最大的好處就是我們最后得到的外圍類是通過構造器構建的! */ private Object readResolve() { return new Persion(desc,name); } } /** * 外圍類直接替換成靜態(tài)內部代理類作為真正的序列化對象 * @return */ private Object writeReplace() { return new SerializableProxy(this); } /** * 這里主要是為了防止攻擊,任何以Persion聲明的對象字節(jié)流都是流氓!! * 因為我在writeReplace中已經(jīng)把序列化的實例指向了SerializableProxy * @param stream * @throws InvalidObjectException */ private void readObject(ObjectInputStream stream) throws InvalidObjectException { throw new InvalidObjectException("proxy requied!"); } }
查看 serialVersionUID 的方法
-
.dat方法查詢 Link不推薦 - serialver 命令 Link
cd 到 java 文件目錄, java文件直接javac 類名.class
編譯, 并serialver 類名
, android 需要將文件刪掉包名, 并沒有父類或父類也跟著復制過來
Parcelable
Parcel
是一系列java通過C++調用內存的操作, 將序列化的數(shù)據(jù)寫入共享內存, 實現(xiàn)跨進程通信
- 根據(jù)這句宏定義得出,Link
#define PAD_SIZE(s) (((s)+3)&~3
內存存放機制和C++的結構體的內存對齊一樣, 即讀取最小字節(jié)位32bit(4字節(jié)), 如果高于4字節(jié), 以實際數(shù)據(jù)類型存放, 但得為4的倍數(shù)
- 占用 32 bit,(<= 32 bit), 例如: boolean, char, int
- 實際占用字節(jié)(> 32 bit), 例如: long, float, String, 數(shù)組等
由此可以知道, 當我們寫入/讀取一個數(shù)據(jù)時, 偏移量至少為4Byte, 偏移量公式
f(x) = 4 * x (x=0, 1, ...)
- writeXXX 和 readXXX 導致的偏移量是共用的, 我們在writeInt(23)后, 此時的dataposition = 4, 讀取的時候, 我們需要將偏移量置為0, 再從0開始讀取4個字節(jié), 所以需要先
setDataPosition(0)
, 再readInt(). - 如果預分配的空間不夠時newSize = ((mDataSize+len) * 3)/2;會一次多分配50%北启;
- 對于不同數(shù)據(jù)的存儲不一樣
- 對于普通數(shù)據(jù), 使用的是 mData 內存地址,
- 對于IBinder 或者 FileDescriptor, 使用的是 mObjects 內存地址, 通過 flatten_binder() 和 unflatten_binder()實現(xiàn), 目的是反序列化時讀出的對象就是愿對象而不是 new 出來的新對象
測試BinderData 但是目前已經(jīng)不能找不到 BinderData 這個類
有兩個成員
uint8_t* mData; //用來存儲序列化流數(shù)據(jù)诀黍,可以把它理解成共享內存
size_t* mObjects; //用來存儲IBinder和FileDescriptor
引用和IBinder的序列化方式不一樣
過程
- 序列化
- 基本類型直接 writeString / writeInt 然后調用 nativeWriteString / nativeWriteInt 用C++操作
- 包含的子類用 writeToParcel 把類名還是用 nativeWriteString 傳給C++操作
- 反序列化
- CREATOR
- createFromParcel 中從流中new出對象和
return new Pojo(in);
- CREATOR
Serializable 完整傳遞過程
結論: Intent 傳遞的 Serializable 數(shù)據(jù)最后還是由 Parcel 傳遞給 C++ 操作, 但是 比普通的 Parcel 數(shù)據(jù)多了調用 Stream 的 I/O 操作
傳遞是靠這兩句
intent.putExtra("myserializabledata", persion);
startActivity(intent);
先看第一句
- Intent.putExtra
public Intent putExtra(String name, Serializable value) {
if (mExtras == null) {
mExtras = new Bundle();
}
//調用了 Bundle.putSerializable
mExtras.putSerializable(name, value);
return this;
}
- -> Bundle.putSerializable
@Override
public void putSerializable(@Nullable String key, @Nullable Serializable value) {
//調用了BaseBundle.putSerializable
super.putSerializable(key, value);
}
- -> BaseBundle.putSerializable
void putSerializable(@Nullable String key, @Nullable Serializable value) {
unparcel();
//數(shù)據(jù)存在 BaseBundle.mMap
mMap.put(key, value);
}
最后將 Serializable 存在了 BaseBundle 的 mMap.
再看第二句
- startActivity 可以理解為最后由 ActivityManager 執(zhí)行, 而ActivityManager在源碼中各版本不一定一致, 先看4.4.4的
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, String profileFile,
ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
...
if (options != null) {
data.writeInt(1);
//這里調用 Bundle.writeToParcel
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
...
return result;
}
- -> Bundle.writeToParcel
@Override
public void writeToParcel(Parcel parcel, int flags) {
final boolean oldAllowFds = parcel.pushAllowFds((mFlags & FLAG_ALLOW_FDS) != 0);
try {
//調用 BaseBundle.writeToParcelInner
super.writeToParcelInner(parcel, flags);
} finally {
parcel.restoreAllowFds(oldAllowFds);
}
}
- -> BaseBundle.writeToParcelInner(parcel, flags)
void writeToParcelInner(Parcel parcel, int flags) {
// Keep implementation in sync with writeToParcel() in
// frameworks/native/libs/binder/PersistableBundle.cpp.
final Parcel parcelledData;
synchronized (this) {
parcelledData = mParcelledData;
}
if (parcelledData != null) {
if (isEmptyParcel()) {
parcel.writeInt(0);
} else {
int length = parcelledData.dataSize();
parcel.writeInt(length);
parcel.writeInt(BUNDLE_MAGIC);
parcel.appendFrom(parcelledData, 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
parcel.writeArrayMapInternal(mMap);
int endPos = parcel.dataPosition();
// Backpatch length
parcel.setDataPosition(lengthPos);
int length = endPos - startPos;
parcel.writeInt(length);
parcel.setDataPosition(endPos);
}
}
- -> Parcel.writeArrayMapInternal(mMap)
void writeArrayMapInternal(ArrayMap<String, Object> val) {
if (val == null) {
writeInt(-1);
return;
}
// Keep the format of this Parcel in sync with writeToParcelInner() in
// frameworks/native/libs/binder/PersistableBundle.cpp.
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++) {
if (DEBUG_ARRAY_MAP) startPos = dataPosition();
writeString(val.keyAt(i));
//開始操作 map 中的 value
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));
}
}
這里操作了第一步生成的 mMAp
- -> parcel.writeValue
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 PersistableBundle) {
writeInt(VAL_PERSISTABLEBUNDLE);
writePersistableBundle((PersistableBundle) v);
} else if (v instanceof Parcelable) {
// IMPOTANT: cases for classes that implement Parcelable must
// come before the Parcelable case, so that their specific VAL_*
// types will be written.
writeInt(VAL_PARCELABLE);
writeParcelable((Parcelable) v, 0);
} else {
Class<?> clazz = v.getClass();
if (clazz.isArray() && clazz.getComponentType() == Object.class) {
// Only pure Object[] are written here, Other arrays of non-primitive types are
// handled by serialization as this does not record the component type.
writeInt(VAL_OBJECTARRAY);
writeArray((Object[]) v);
} else if (v instanceof Serializable) {
// Must be last
writeInt(VAL_SERIALIZABLE);
//對 Serializable 操作
writeSerializable((Serializable) v);
} else {
throw new RuntimeException("Parcel: unable to marshal value " + v);
}
}
}
在writeValue的最后,處理了 Serializable
- -> Parcel.writeSerializable()
public final void writeSerializable(Serializable s) {
if (s == null) {
writeString(null);
return;
}
String name = s.getClass().getName();
writeString(name);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(s);
oos.close();
//將Serializable I/O操作后轉換成字節(jié)流
writeByteArray(baos.toByteArray());
} catch (IOException ioe) {
throw new RuntimeException("Parcelable encountered " +
"IOException writing serializable object (name = " + name +
")", ioe);
}
}
- -> Parcel.writeByteArray()
public final void writeByteArray(byte[] b) {
//對流判斷
writeByteArray(b, 0, (b != null) ? b.length : 0);
}
- -> Parcel.nativeWriteByteArray()
public final void writeByteArray(byte[] b, int offset, int len) {
if (b == null) {
writeInt(-1);
return;
}
Arrays.checkOffsetAndCount(b.length, offset, len);
//調用了 native 方法
nativeWriteByteArray(mNativePtr, b, offset, len);
}
Intent
Intent 的 bundle 使用Binder機制進行數(shù)據(jù)傳遞, 能使用Binder的緩沖區(qū)有大小限制, 有些手機是2M
一個進程默認有16個 Binder線程, 所以一個線程所能占用的緩沖區(qū)更小了(大約一個線程128KB), 所以當出現(xiàn)The Binder transaction failed because it was too large, 說明數(shù)據(jù)太大.
因此Intent傳遞List和Bitmap對象是存在風險的
參考