Android Intent傳遞數(shù)據(jù)底層分析詳細(xì)介紹
Android Intent傳遞數(shù)據(jù)底層分析詳細(xì)介紹
我們知道在Activity切換時(shí),如果需要向下一個(gè)ActivityB傳遞數(shù)據(jù),可以借助Intent對(duì)象的putExtra方法。
但是不知各位有沒(méi)有想過(guò)這樣一個(gè)問(wèn)題:ActivityB中獲取到的對(duì)象跟上一個(gè)Activity中的那個(gè)對(duì)象有什么關(guān)系?
換句話(huà)說(shuō)就是,我在ActivityB中通過(guò)Intent獲取的對(duì)象跟ActivityA中的那個(gè)對(duì)象,有沒(méi)有可能是同一個(gè)對(duì)象?
按照常理來(lái)說(shuō),博主提出一個(gè)設(shè)想后續(xù)的就是證明過(guò)程了,但是我要遺憾的告訴你,這里并非是同一個(gè)對(duì)象。(PS:廢話(huà),如果是同一個(gè)對(duì)象,那還有EventBus這些東西什么事兒 T_T)
那么問(wèn)題又來(lái)了,這兩個(gè)Activity都在同一個(gè)進(jìn)程里面,甚至都在同一個(gè)線(xiàn)程里面,數(shù)據(jù)本來(lái)就是可以共享的,為什么從一個(gè)Activity傳到另一個(gè)Activity之后,就不是一個(gè)對(duì)象了呢?它從什么時(shí)候變成另外的對(duì)象的呢?
不著急,且聽(tīng)我慢慢道來(lái)。
Intent是什么東西?
public class Intent implements Parcelable, Cloneable
上面是Intent類(lèi)的完整聲明,可以知道它實(shí)現(xiàn)了Parcelable接口。Parcelable接口是什么呢?這東西是Android上專(zhuān)門(mén)用來(lái)對(duì)數(shù)據(jù)進(jìn)行序列化的,并且在跨進(jìn)程通訊時(shí)Parceable對(duì)象是可以直接傳輸?shù)摹?
接下來(lái)我們來(lái)看看將數(shù)據(jù)放入Intent的時(shí),做了哪些處理。
以String為例,先看putExtra方法的代碼
public Intent putExtra(String name, String value) { if (mExtras == null) { mExtras = new Bundle(); } mExtras.putString(name, value); return this; }
很簡(jiǎn)單,就是將數(shù)據(jù)放入mExtras這個(gè)Bundle對(duì)象中,順便說(shuō)一句Bundle類(lèi)也實(shí)現(xiàn)了Parcelable接口。繼續(xù)往下跟代碼
public void putString(@Nullable String key, @Nullable String value) { unparcel(); mMap.put(key, value); }
內(nèi)部就是將數(shù)據(jù)放入一個(gè)Map中保存。到這里數(shù)據(jù)放入Intent的過(guò)程就完成了,實(shí)際上就是Intent中有一個(gè)Bundle對(duì)象,而這個(gè)Bundle對(duì)象中又有一個(gè)Map,然后數(shù)據(jù)就保存在這里。至于那個(gè)unparcel()方法與我們的分析過(guò)程無(wú)關(guān),有興趣的讀者可以去研究一下。
然后,我們?cè)倏慈?shù)據(jù)的過(guò)程。
繼續(xù)以String作為例子,看Intent中的代碼
public String getStringExtra(String name) { return mExtras == null ? null : mExtras.getString(name); }
mExtras應(yīng)該很熟悉了,這是個(gè)Bundle對(duì)象,剛剛保存數(shù)據(jù)的時(shí)候就是把數(shù)據(jù)保存在它里面的。再看它的getString方法
public String getString(@Nullable String key) { unparcel(); final Object o = mMap.get(key); try { return (String) o; } catch (ClassCastException e) { typeWarning(key, o, "String", e); return null; } }
就是直接從Map里面拿出我們之前保存的String,try語(yǔ)句只是在驗(yàn)證取出的數(shù)據(jù)是否為String類(lèi)型。
那照這么分析的話(huà),兩個(gè)Activity中的對(duì)象應(yīng)該就是同一個(gè)對(duì)象才對(duì)?。?!為什么又說(shuō)不是同一個(gè)對(duì)象呢?
為什么不是同一個(gè)對(duì)象?
如果你在putExtra之后,馬上又getExtra出來(lái),那么你取出來(lái)的對(duì)象肯定是同一個(gè)對(duì)象,這個(gè)沒(méi)錯(cuò)!
但是這里我們要注意兩點(diǎn):
1.Intent中允許保存的數(shù)據(jù)類(lèi)型是有限制的,準(zhǔn)確的說(shuō)是Bundle的限制,因?yàn)閷?shí)質(zhì)上數(shù)據(jù)是保存在Bundle中。如果我們要保存自己定義的對(duì)象,那么我們的對(duì)象必須實(shí)現(xiàn)了Parcelable接口或者Serializable接口。
2.我們使用Intent的方式,基本都是在一個(gè)Activity中存入,然后從另一個(gè)Activity中取出。
那么問(wèn)題很明顯就出在Activity的啟動(dòng)過(guò)程了。詳細(xì)的啟動(dòng)過(guò)程大家可以參考老羅的文章Activity啟動(dòng)過(guò)程。
這里大概說(shuō)一下,首先我們的app運(yùn)行在app自己的進(jìn)程appProcess中,然后系統(tǒng)在啟動(dòng)的時(shí)候會(huì)啟動(dòng)一個(gè)系統(tǒng)進(jìn)程systemProcess。而在Activity啟動(dòng)時(shí),需要向一個(gè)叫做ActivityManagerService的系統(tǒng)服務(wù)去注冊(cè),這樣我們的Activity才能有生命周期的回調(diào)。這個(gè)ActivityManagerService服務(wù)就運(yùn)行在systemProcess中。注冊(cè)完之后,再回到appProcess中,完成新Activity的啟動(dòng)。在這個(gè)注冊(cè)過(guò)程中,我們的intent是全程參與的。
說(shuō)到這里就明白了,當(dāng)我們調(diào)用startActivity(intent)啟動(dòng)另外的Activity的時(shí)候,我們的intent已經(jīng)完成了兩次跨進(jìn)程通信,而它里面的對(duì)象已經(jīng)經(jīng)歷了兩輪序列化和反序列化,肯定不可能是同一個(gè)對(duì)象了。
這里順便說(shuō)一個(gè)問(wèn)題:為什么Serializable也可以跨進(jìn)程傳輸?
熟悉AIDL的同學(xué)都很清楚,AIDL跨進(jìn)程通信支持的數(shù)據(jù)類(lèi)型是:
- Java 的原生類(lèi)型,如int,boolean,long,float…
- String 和CharSequence
- List 和 Map ,List和Map 對(duì)象的元素必須是AIDL支持的數(shù)據(jù)類(lèi)型
- AIDL 自動(dòng)生成的接口 需要導(dǎo)入(import)
- 實(shí)現(xiàn)android.os.Parcelable 接口的類(lèi). 需要導(dǎo)入(import)。
這里并不包括Serializable類(lèi)型。
于是去看了源碼,發(fā)現(xiàn)是Parcel自己對(duì)Serializable類(lèi)型的對(duì)象做了兼容,可以直接寫(xiě)入其中。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Android輕量級(jí)存儲(chǔ)SharedPreferences?MMKV?Jetpack?DataStore方案
這篇文章主要為大家介紹了Android輕量級(jí)存儲(chǔ)SharedPreferences?MMKV?Jetpack?DataStore方案示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08Kotlin下Rxjava的基礎(chǔ)用法及流式調(diào)用示例詳解
這篇文章主要為大家介紹了Kotlin下Rxjava的基礎(chǔ)用法及流式調(diào)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Android 實(shí)現(xiàn)不依賴(lài)焦點(diǎn)和選中的TextView跑馬燈
本文主要介紹Android 跑馬燈的實(shí)現(xiàn),這里提供實(shí)現(xiàn)詳細(xì)實(shí)現(xiàn)代碼供大家參考,有需要的小伙伴可以看下2016-07-07Android Toast的幾種使用方式及注意事項(xiàng)
Toast是Android中常用的組件,下面介紹下Toast使用的幾種方式和注意事項(xiàng),本文給大家分享Toast的使用方式,感興趣的朋友一起看看吧2024-02-02探討Android 的屏幕滾動(dòng)操作不如 iPhone 流暢順滑的原因
雖然很多Android手機(jī)的配置都比iPhone要高,比如大多數(shù)Andorid手機(jī)的內(nèi)存都有1GB,而iPhone 4S只有512MB內(nèi)存,但用過(guò)iPhone的人都知道Android手機(jī)在使用的時(shí)候總感覺(jué)沒(méi)有那么順滑,究竟為什么會(huì)出現(xiàn)這種現(xiàn)象呢?2014-07-07在Android項(xiàng)目中使用AspectJ的方法
這篇文章主要介紹了在Android項(xiàng)目中使用AspectJ的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Android 全局Dialog的簡(jiǎn)單實(shí)現(xiàn)方法
本篇文章主要介紹了Android 全局Dialog的簡(jiǎn)單實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02Android實(shí)現(xiàn)通訊錄效果——獲取手機(jī)號(hào)碼和姓名
這篇文章主要介紹了Android實(shí)現(xiàn)通訊錄效果——獲取手機(jī)號(hào)碼和姓名的相關(guān)資料,需要的朋友可以參考下2016-03-03Android GSYVideoPlayer視頻播放器功能的實(shí)現(xiàn)
這篇文章主要介紹了Android GSYVideoPlayer視頻播放器功能的實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03