Android開發(fā) Bundle傳值的理解與使用小結(jié)
什么是Bundle
Bundle經(jīng)常出現(xiàn)在以下場(chǎng)合:
Activity狀態(tài)數(shù)據(jù)的保存與恢復(fù)涉及到的兩個(gè)回調(diào): void onSaveInstanceState (Bundle outState) void onCreate (Bundle savedInstanceState) Fragment的setArguments方法:void setArguments (Bundle args) 消息機(jī)制中的Message的setData方法:void setData (Bundle data) ...
Bundle從字面上解釋為“一捆、一批、一包”,結(jié)合上述幾個(gè)應(yīng)用場(chǎng)合,可以知道Bundle是用來(lái)傳遞數(shù)據(jù)的。我們經(jīng)常使用Bundle在Activity之間傳遞數(shù)據(jù),傳遞的數(shù)據(jù)可以是boolean、byte、int、long、float、double、string等基本類型或它們對(duì)應(yīng)的數(shù)組,也可以是對(duì)象或?qū)ο髷?shù)組。當(dāng)Bundle傳遞的是對(duì)象或?qū)ο髷?shù)組時(shí),必須實(shí)現(xiàn)Serializable 或Parcelable接口。下面分別介紹Activity之間如何傳遞基本類型、傳遞對(duì)象:
Bundle的兩個(gè)常用方法:
putXxx(String key,Xxx value)
:Xxx表示一系列的數(shù)據(jù)類型,比如String、int、float、Parcelable、Serializable等類型,以“鍵值對(duì)”(key-value,可以理解為一個(gè)Map<K,V>)
形式保存數(shù)據(jù)getXxx(String key)
:根據(jù)key值獲取Bundle中的value數(shù)據(jù)
Bundle源碼分析
Bundle的聲明
public final class Bundle extends BaseBundle implements Cloneable, Parcelable
:可以看出以下幾點(diǎn):
它使用final修飾,所以不可以被繼承
它實(shí)現(xiàn)了兩個(gè)接口,cloneable(復(fù)制)和Parcelable(打包),這就意味著他必須實(shí)現(xiàn)以下方法:
public Object clone() //克隆數(shù)據(jù) public int describeContents() //寫入數(shù)據(jù) public void writeToParcel(Parcel parcel, int flags) //將數(shù)據(jù)打包 public void readFromParcel(Parcel parcel) //讀取數(shù)據(jù) public static final Parcelable.Creator<Bundle> CREATOR = new Parcelable.Creator<Bundle>() //將打包的數(shù)據(jù)實(shí)例化
Bundle的內(nèi)存結(jié)構(gòu)
ArrayMap<String, Object> mMap = null;
:使用的是ArrayMap,這個(gè)集合類存儲(chǔ)的也是鍵值對(duì),但是與Hashmap不同的是,hashmap采用的是“數(shù)組+鏈表”的方式存儲(chǔ),而Arraymap中使用的是兩個(gè)數(shù)組進(jìn)行存儲(chǔ),一個(gè)數(shù)組存儲(chǔ)key,一個(gè)數(shù)組存儲(chǔ)value,內(nèi)部的增刪改查都將會(huì)使用二分查找來(lái)進(jìn)行,這個(gè)和SparseArray差不多,只不過(guò)sparseArray的key值只能是int類型的,而Arraymap可以是map型,所以在數(shù)據(jù)量不大的情況下可以使用這兩個(gè)集合代替hashmap去優(yōu)化性能
Get/Put解析
Bundle其實(shí)就是一個(gè)容器,內(nèi)部使用了Arraymap去存儲(chǔ)數(shù)據(jù),那么就必然會(huì)提供get與put方法,由于Bundle支持的數(shù)據(jù)類型太多,這里我們就舉例布爾類型的,其他類型的方式都差不多:
getBoolean:
public boolean getBoolean(String key, boolean defaultValue) { unparcel(); Object o = mMap.get(key); if (o == null) { return defaultValue; } try { return (Boolean) o; } catch (ClassCastException e) { typeWarning(key, o, "Boolean", defaultValue, e); return defaultValue; } }
數(shù)據(jù)讀取的邏輯就是通過(guò)key從ArrayMap里讀出保存的數(shù)據(jù),并轉(zhuǎn)換成對(duì)應(yīng)的類型返回,當(dāng)沒找到數(shù)據(jù)或發(fā)生類型轉(zhuǎn)換異常時(shí)返回缺省值(default-value
類似null的空值)putBoolean:
public void putBoolean(@Nullable String key, boolean value) { unparcel(); mMap.put(key, value); }
unparcel():
先來(lái)看下BaseBundle中mParcelledData的定義:
Parcel mParcelledData = null;
在大部分情況下mParcelledData都是null,因此unparcel()
直接返回。當(dāng)使用構(gòu)造函數(shù)public Bundle(Bundle b)
創(chuàng)建Bundle時(shí),會(huì)給mParcelledData賦值;
oid copyInternal(BaseBundle from, boolean deep) { synchronized (from) { if (from.mParcelledData != null) { if (from.isEmptyParcel()) { mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL; //第一種取值 } else { mParcelledData = Parcel.obtain(); //第二種取值 mParcelledData.appendFrom(from.mParcelledData, 0, from.mParcelledData.dataSize()); mParcelledData.setDataPosition(0); } } else { mParcelledData = null; //第三種取值 } if (from.mMap != null) { if (!deep) { mMap = new ArrayMap<>(from.mMap); } else { final ArrayMap<String, Object> fromMap = from.mMap; final int N = fromMap.size(); mMap = new ArrayMap<>(N); for (int i = 0; i < N; i++) { mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i))); } } } else { mMap = null; } mClassLoader = from.mClassLoader; } }
從上述代碼片段可以知道mParcelledData的取值有3種情況:
mParcelledData = EMPTY_PARCEL
mParcelledData = Parcel.obtain()
mParcelledData = null
總結(jié)
- 在
unparcel()
方法中就對(duì)上述幾種情況做了不同的處理,當(dāng)mParcelledData = null
時(shí),直接返回 - 當(dāng)
mParcelledData = EMPTY_PARCEL
時(shí),會(huì)創(chuàng)建一個(gè)容量為1的ArrayMap對(duì)象 - 當(dāng)
mParcelledData = Parcel.obtain()
時(shí),則會(huì)將里面的數(shù)據(jù)讀出,并創(chuàng)建一個(gè)ArrayMap,并將數(shù)據(jù)存儲(chǔ)到ArrayMap對(duì)象里面,同時(shí)將mParcelledData回收并置為null
Bundle的使用
各種常用類型的Put/Get方法
Bundle提供了,用于讀寫基本類型的數(shù)據(jù)。Bundle操作基本數(shù)據(jù)類型的API表格如下所示:
傳遞基本類型的對(duì)象
數(shù)據(jù)打包
Bundle bundle = new Bundle(); Intent intent = new Intent(MainActivity.this,Main2Activity.class); //設(shè)置數(shù)據(jù) String name = "zhangSan"; String num = "88888"; //把數(shù)據(jù)保存到Bundle里 bundle.putString("name", name); bundle.putString("num", num); //把bundle放入intent里 intent.putExtra("Message", bundle); startActivity(intent);//開始打包
讀取數(shù)據(jù)
Intent intent = getIntent(); //實(shí)例化一個(gè)Bundle Bundle bundle = intent.getExtras(); String name = bundle.getString("name"); String num = bundle.getString("num");
Activity通過(guò)Arguments給fragment類傳值
當(dāng)Activity類動(dòng)態(tài)加載fragment時(shí)可以通過(guò)fragment的setArguments()
傳入值,并在fragment類中通過(guò)fragment的getArguments()
方法獲得傳入的值。
數(shù)據(jù)打包
Bundle bundle = new Bundle(); fragment01 fragment01 = new fragment01();//自定義的fragment類 //設(shè)置數(shù)據(jù) String name = "zhangSan"; String num = "88888"; //把數(shù)據(jù)保存到Bundle里 bundle.putString("name", name); bundle.putString("num", num); //把bundle通過(guò)Arguments放入要傳值的fragment類里 fragment01.setArguments(bundle);
讀取數(shù)據(jù)
String name = getArguments().getString("name"); String num = getArguments().getString("num");
傳遞Serializable類型的對(duì)象
Serializable:是一個(gè)對(duì)象序列化的接口。一個(gè)類只有實(shí)現(xiàn)了Serializable接口,它的對(duì)象才是可序列化的。因此如果要序列化某些類的對(duì)象,這些類就必須實(shí)現(xiàn)Serializable接口。而實(shí)際上,Serializable是一個(gè)空接口,沒有什么具體內(nèi)容,它的目的只是簡(jiǎn)單的標(biāo)識(shí)一個(gè)類的對(duì)象可以被序列化
打包數(shù)據(jù)
People people = new people(); //People類 //設(shè)置數(shù)據(jù) String Name = "zhangSan"; String Num = "88888"; people.setName(Name); people.setNum(Num); //實(shí)例化一個(gè)Bundle Bundle bundle = new Bundle(); //把people數(shù)據(jù)放入到bundle中 bundle.putSerializable("people", people); Intent intent = new Intent(MainActivity.this,Main2Activity.class); //把bundle放入intent里 intent.putExtras(bundle); startActivity(intent);//開始打包
讀取數(shù)據(jù)
Intent intent = getIntent(); // 實(shí)例化一個(gè)Bundle Bundle bundle = intent.getExtras(); //獲取里面的people里面的數(shù)據(jù) People people = (people) bundle.getSerializable("people"); String name = people.getName(); String num = people.getNum();
到此這篇關(guān)于Android開發(fā) Bundle傳值的理解與使用的文章就介紹到這了,更多相關(guān)Android Bundle傳值內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android中傳值Intent與Bundle的區(qū)別小結(jié)
- android中Intent傳值與Bundle傳值的區(qū)別詳解
- Android 中為什么要用Fragment.setArguments(Bundle bundle)來(lái)傳遞參數(shù)
- Android 通過(guò)Intent使用Bundle傳遞對(duì)象詳細(xì)介紹
- 利用adt-bundle輕松搭建Android開發(fā)環(huán)境與Hello world(Linux)
- 利用adt-bundle輕松搭建Android開發(fā)環(huán)境與Hello world(Windows)
- Android 幾種屏幕間跳轉(zhuǎn)的跳轉(zhuǎn)Intent Bundle
相關(guān)文章
Android使用百度地圖出現(xiàn)閃退及定位時(shí)顯示藍(lán)屏問(wèn)題的解決方法
這篇文章主要介紹了Android使用百度地圖出現(xiàn)閃退及定位時(shí)顯示藍(lán)屏問(wèn)題的解決方法,需要的朋友可以參考下2018-01-01Android自定義View實(shí)現(xiàn)數(shù)獨(dú)游戲
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)數(shù)獨(dú)游戲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12android獲取手機(jī)唯一標(biāo)識(shí)的方法
這篇文章主要介紹了獲取安卓的手機(jī)或者平板的唯一標(biāo)識(shí)的方法,需要的朋友可以參考下2014-02-02Android 媒體開發(fā)之MediaPlayer狀態(tài)機(jī)接口方法實(shí)例解析
這篇文章主要介紹了Android 媒體開發(fā)之MediaPlayer狀態(tài)機(jī)接口方法實(shí)例解析,需要的朋友可以參考下2017-08-08Android TextView實(shí)現(xiàn)詞組高亮的示例代碼
本篇文章主要介紹了Android TextView實(shí)現(xiàn)詞組高亮的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10Android之在linux終端執(zhí)行shell腳本直接打印當(dāng)前運(yùn)行app的日志的實(shí)現(xiàn)方法
今天小編就為大家分享一篇關(guān)于Android之在linux終端執(zhí)行shell腳本直接打印當(dāng)前運(yùn)行app的日志的實(shí)現(xiàn)方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02Android 使用Path實(shí)現(xiàn)涂鴉功能
到月底了最近比較空閑,今天抽空給大家實(shí)現(xiàn)一個(gè)涂鴉效果,會(huì)分幾步實(shí)現(xiàn),這里有一個(gè)重要的知識(shí)點(diǎn)就是圖層,要理解這個(gè)。下面先從簡(jiǎn)單的說(shuō)起,一起看看代碼吧2016-12-12