面試題:兩個Activity之間如何傳遞參數?
在Android應用中,Activity占有極其重要的地位,Activity間的跳轉更是加常便飯。即然跳轉(界面切換)不可避免,那么在兩個Activity之間傳遞參數就是一個常見的需求。大多數時候,我們也就傳遞一些簡單的int,String類型的數據,實際中也有看到傳遞List和Bitmap的。
那么我們先回答這個題,如何傳遞參數:
使用Intent的Bundle協帶參數,就是我們常用的Intent.putExtra方法。
做為面試官,緊接著可以問:除了傳遞基本類型外,如何傳遞自定義的對象呢?
這個問題就是想引出Android的Parcelable。一般很多面試者都有用過傳遞實現了Serializable接口的自定義對象的經驗,因為這個很簡單,加句代碼就搞定了。而Parcelable的實現要多一些代碼,典型的寫法如下:
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<MyParcelable> CREATOR
= new Parcelable.Creator<MyParcelable>() {
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();
}
}
那我們為什么要考察對方會不會用Parcelable呢?先看一下這Parcelable和Serializable的區別:
Serializalbe會使用反射,序列化和反序列化過程需要大量I/O操作,Parcelable自已實現封送和解封(marshalled &unmarshalled)操作不需要用反射,數據也存放在Native內存中,效率要快很多。
有人比較過它們兩個的效率差別:
不同類型的數據不一定差據這么大,但卻很直觀的展示了Pacelable比Serializable高效。
有時面試官還可以追問一下:Parcelable和Parcle這兩者之間的關系。
Parcelable 接口定義在封送/解封送過程中混合和分解對象的契約。Parcelable接口的底層是Parcel容器對象。Parcel類是一種最快的序列化/反序列化機制,專為Android中的進程間通信而設計。該類提供了一些方法來將成員容納到容器中,以及從容器展開成員。
現在我們知道了如何傳遞自定義的對象,那么在兩個Activity之前傳遞對象還要注意什么呢?
一定要要注意對象的大小,Intent中的Bundle是在使用Binder機制進行數據傳遞的,能使用的Binder的緩沖區是有大小限制的(有些手機是2M),而一個進程默認有16個binder線程,所以一個線程能占用的緩沖區就更小了(以前做過測試,大約一個線程可以占用128KB)。所以當你看到“The Binder transaction failed because it was too large.”這類TransactionTooLargeException異常時,你應該知道怎么解決了。
因此,使用Intent在Activity之間傳遞List和Bitmap對象是有風險的。
面試官可以就這個問題再展開,看面試者如何解決。
還有一個要注意的:因為android不同版本Parcelable可能不同,所以不推薦使用Parcelable進行數據持久化。之前我有過一次,將Android的PackageInfo進行持久化到數據庫,結果用戶升級Android系統后,再從數據庫解封PackageInfo時應用就Crash了。
結論
對于初級的程序員來說,只要能抓住老鼠,白貓或者黑貓甚至是小狗都是沒有區別的。但對于應用的流暢和體驗來說,100毫秒和1000毫秒是有很大區別的。很多程序員眼里無關緊要的差別,最終在用戶那兒會被幾倍十幾倍的放大,老板也會因為用戶的投述而斥責你。因為總會有用戶在用性能很差的手機,總有用戶手機的使用情況很復雜(內存緊張,網絡復雜等等),總有用戶本人就很奇葩不會按你指定的套路出拳!當你鄙視老板不懂代碼的藝術時,老板也會鄙視你不懂用戶不懂細節的重要性,活該你一輩子做程序員。
所以,在能使用的Parcelable的地方,請不要貪圖簡便直接Serializable,實在懶的話也可以試試用插件自動生成Pracelabel的模板代碼:android-parcelable-intellij-plugin