1. 程式人生 > >Intent傳遞資料底層分析

Intent傳遞資料底層分析

我們知道在Activity切換時,如果需要向下一個ActivityB傳遞資料,可以藉助Intent物件的putExtra方法。 
但是不知各位有沒有想過這樣一個問題:ActivityB中獲取到的物件跟上一個Activity中的那個物件有什麼關係? 
換句話說就是,我在ActivityB中通過Intent獲取的物件跟ActivityA中的那個物件,有沒有可能是同一個物件? 
按照常理來說,博主提出一個設想後續的就是證明過程了,但是我要遺憾的告訴你,這裡並非是同一個物件。(PS:廢話,如果是同一個物件,那還有EventBus這些東西什麼事兒 T_T) 
那麼問題又來了,這兩個Activity都在同一個程序裡面,甚至都在同一個執行緒裡面,資料本來就是可以共享的,為什麼從一個Activity傳到另一個Activity之後,就不是一個物件了呢?它從什麼時候變成另外的物件的呢? 
不著急,且聽我慢慢道來。

Intent是什麼東西?

public class Intent implements Parcelable, Cloneable

上面是Intent類的完整宣告,可以知道它實現了Parcelable介面。Parcelable介面是什麼呢?這東西是Android上專門用來對資料進行序列化的,並且在跨程序通訊時Parceable物件是可以直接傳輸的。 
接下來我們來看看將資料放入Intent的時,做了哪些處理。 
以String為例,先看putExtra方法的程式碼

public Intent putExtra(String name, String value) {
        if (mExtras == null
) { mExtras = new Bundle(); } mExtras.putString(name, value); return this; }

很簡單,就是將資料放入mExtras這個Bundle物件中,順便說一句Bundle類也實現了Parcelable介面。繼續往下跟程式碼

public void putString(@Nullable String key, @Nullable String value) {
        unparcel();
        mMap.put(key, value
); }

內部就是將資料放入一個Map中儲存。到這裡資料放入Intent的過程就完成了,實際上就是Intent中有一個Bundle物件,而這個Bundle物件中又有一個Map,然後資料就儲存在這裡。至於那個unparcel()方法與我們的分析過程無關,有興趣的讀者可以去研究一下。 
然後,我們再看取資料的過程。 
繼續以String作為例子,看Intent中的程式碼

public String getStringExtra(String name) {
        return mExtras == null ? null : mExtras.getString(name);
    }

mExtras應該很熟悉了,這是個Bundle物件,剛剛儲存資料的時候就是把資料儲存在它裡面的。再看它的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語句只是在驗證取出的資料是否為String型別。 
那照這麼分析的話,兩個Activity中的物件應該就是同一個物件才對啊!!為什麼又說不是同一個物件呢?

為什麼不是同一個物件?

如果你在putExtra之後,馬上又getExtra出來,那麼你取出來的物件肯定是同一個物件,這個沒錯! 
但是這裡我們要注意兩點: 
1.Intent中允許儲存的資料型別是有限制的,準確的說是Bundle的限制,因為實質上資料是儲存在Bundle中。如果我們要儲存自己定義的物件,那麼我們的物件必須實現了Parcelable介面或者Serializable介面。 
2.我們使用Intent的方式,基本都是在一個Activity中存入,然後從另一個Activity中取出。 
那麼問題很明顯就出在Activity的啟動過程了。詳細的啟動過程大家可以參考老羅的文章Activity啟動過程。 
這裡大概說一下,首先我們的app執行在app自己的程序appProcess中,然後系統在啟動的時候會啟動一個系統程序systemProcess。而在Activity啟動時,需要向一個叫做ActivityManagerService的系統服務去註冊,這樣我們的Activity才能有生命週期的回撥。這個ActivityManagerService服務就執行在systemProcess中。註冊完之後,再回到appProcess中,完成新Activity的啟動。在這個註冊過程中,我們的intent是全程參與的。 
說到這裡就明白了,當我們呼叫startActivity(intent)啟動另外的Activity的時候,我們的intent已經完成了兩次跨程序通訊,而它裡面的物件已經經歷了兩輪序列化和反序列化,肯定不可能是同一個物件了。

這裡順便說一個問題:為什麼Serializable也可以跨程序傳輸? 
熟悉AIDL的同學都很清楚,AIDL跨程序通訊支援的資料型別是:

  1. Java 的原生型別,如int,boolean,long,float…
  2. String 和CharSequence
  3. List 和 Map ,List和Map 物件的元素必須是AIDL支援的資料型別
  4. AIDL 自動生成的介面 需要匯入(import)
  5. 實現android.os.Parcelable 介面的類. 需要匯入(import)。

這裡並不包括Serializable型別。 
於是去看了原始碼,發現是Parcel自己對Serializable型別的物件做了相容,可以直接寫入其中。

相關推薦

Intent傳遞資料底層分析

我們知道在Activity切換時,如果需要向下一個ActivityB傳遞資料,可以藉助Intent物件的putExtra方法。  但是不知各位有沒有想過這樣一個問題:ActivityB中獲取到的物件跟上一個Activity中的那個物件有什麼關係?  換句話說就是,我在ActivityB中通過Intent獲取

Intent傳遞資料重複問題

Android解決Intent中的資料重複問題 轉載地址:http://www.cnblogs.com/anrainie/articles/2383941.html 最近在研究Android,遇到了一些Notification(通知)的問題: 1、Notification如何傳遞引數

ANDROID----使用Intent傳遞資料----startActivityForResult

eg: //這個是在第一個顯示的Activity中 Intent intent=new Intent(MainActivity.this,otherActivity.class); startActivityForResult(intent,requestCode); 在另外一個Activi

Vue父子vue-router路由傳遞資料與父子元件傳遞資料分析

父子路由傳遞資料 分析如下 實際上等同於父子元件之間,資料的傳遞; 父傳子 ---------> 父繫結屬性,子props接受屬性值 子傳父 ---------> 觸發自定義事件,子觸發$emit,父接收 父元件觸發子事件 ------->

Intent傳遞資料 對於GsonFormat生成的資料需要將裡面的所有內部類實現序列化接口才可打包過去

Intent傳遞資料  對於GsonFormat生成的資料需要將裡面的所有內部類實現序列化接口才可打包過去 Intent intent = new Intent(context,ReYinKouBeiActivity.class);Bundle bundle=new Bu

Android 最全 Intent 傳遞資料姿勢

點選上面藍色字型關注“IT大飛說” 置頂公眾號(ID:ITBigFly)第一時間收到推送 作為一個 Android 開發人員,我們都是用過 Intent,用它來在元件之間傳遞資料,所以說 Intent 是元件之間通訊的使者,一般情況下,我們傳遞的都

Android通過Intent傳遞資料

日常開發中,我們經常遇到通過 Intent 來傳遞資料,預設情況,我們可以看到支援的資料型別: 基本型別:boolean、byte、char 、short、double、float、int、long 字串型別:String、String[]、CharSe

Activity間通過Intent傳遞資料的大小限制。

http://blog.csdn.net/pingfangx/article/details/52093225 這個問題沒找到官方說明,針對網上的各種答案,自己實際測試了一下。 0x01結論 1.1傳512K以下的資料的資料可以正常傳遞。 1.2傳512K~102

android訊息廣播Intent傳遞資料

1.建立佈局檔案activity_broadcast.xml<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/a

Day1 Toast/Menu/Intent傳遞資料

今天是我讀《第二行程式碼》的第一天,也是我第一次開始寫CSDN部落格,之前的筆記都在OneNote上,後來發現OneNote沒有程式碼段功能,不能滿足需求。同時發現CSDN部落格環境挺友好的,在考慮要不要把筆記都複製上來呢。 在活動中使用Toast

Java基本資料型別以及由不可變類帶來的值傳遞和引用傳遞的難點分析

一、Java提供的資料型別 Java提供了8中原始的資料型別(byte,short,int,long,float,double,char,boolean),這些資料型別不是物件,相應的變數被定義後會立刻在棧上被分配記憶體空間。除此之外的資料型別,都是引用型別,引用型別在變數

6.Android的學習(Intent跳轉頁面,活動之間傳遞資料)

Intent跳轉頁面 (1)使用顯示Intent,首先建立一個空的活動,並且有佈局,在onClick()下面新增: Intent裡面的第一個引數是當前活動頁面,第二引數是要跳轉的活動頁面。這段程式碼在當前活動頁面。 2.  (1)向下一個活動傳遞資料  · 主活動介

Android中Intent傳遞自定義物件型別的資料

Android中Intent是用來實現元件之間的通訊的,可以在元件之間傳遞資料。可以傳遞一些基本型別的資料,也可以傳遞自定義物件型別的資料,但是如果要傳遞自定義型別的物件資料,這個自定義型別的物件必須是實現了Serializable介面或者是實現Parcelab

Android Intent傳值(兩個Activity之間傳遞資料

在兩個Activity之間傳遞資料,最終都是通過Intent傳遞,但設定資料和儲存資料方式有兩種(使用Intent 和 Bundle),分別對應如下: 設定資料(MainActivity.java) 方法一:1.直接用intent.putExtra(“name”,“張三”)

使用顯式Intent向下一個活動傳遞資料

在啟動活動時傳遞資料的思路很簡單,Intent提供了一系列putExtra()方法的過載,可以把我們想要傳遞的資料暫存在Intent中,啟動了另一個活動後,只需要把這些資料再從Intent中取出取出就可以了。比如說MainActivity中有一個字串,現在想把這個字元傳遞到SecondActivit

【乾貨】各區塊鏈底層資料儲存分析(一)

網際網路的中心化發展模式是傳統網路安全的的軟肋,區塊鏈作為一種去中心化、集體維護、不可篡改的新興技術,是對網際網路底層架構的革新,是對當今生產力和生產關係的變革。區塊鏈也被譽為是繼蒸汽機、電力、資訊和網際網路科技之後,目前最有潛力觸發第五輪顛覆性革命浪潮的核心技術。 目前

2.3 使用intent物件傳遞資料

除了從intent返回資料之外,也經長需要傳遞資料給activity。 建立一個android專案:PassingData 在activity_main.xml中新增: <RelativeLayout xmlns:android="http://sch

JavaBinder: !!! FAILED BINDER TRANSACTION !!! intent傳遞資料異常解決

    在使用intent傳遞集合資料的時候,報了JavaBinder: !!! FAILED BINDER TRANSACTION !!! 錯誤,翻譯成中文就是“繫結器事務失敗”,實際的原因就是使用intent的時候攜帶的資料太大導致傳遞失敗。    

Android 使用Intent和Bundle傳遞資料及如何傳遞enum

                        轉載請標明出處:

【Android資料傳遞Intent傳遞List和Object和List(附原始碼)

一、傳遞List 傳遞List<String>的方法 ArrayList<String> info = new ArrayList<String>(); info.add(name); info.add(website); inf