欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

從源碼剖析Android中的Intent組件

 更新時間:2016年03月08日 16:14:41   作者:iam_wingjay  
這篇文章主要介紹了Android中的Intent組件,作者從源碼剖析了Intent如何實現(xiàn)組件間的切換,需要的朋友可以參考下

我們知道,Intent主要用來激活安卓幾大組件,那么它具體是怎樣來激活的?激活時是否可以攜帶java對象?為何要將對象序列化后才能傳遞?

一、Intent官網(wǎng)解釋
Intent可以被startActivity用來加載Activity,也可以被broadcastIntent發(fā)送給指定的BroadReceiver組件,
或者被startService、bingService來與后臺service通信。
Intent最主要作用就是加載Activity,好比Activity之間的膠水。
Intent數(shù)據(jù)結(jié)構(gòu):

  • action:所要執(zhí)行的動作;(例如:ACTION_CALL創(chuàng)建打電話Activity;ACTION_BATTERY_LOW 發(fā)出廣播警告電池電量低,)
  • data: 要使用的數(shù)據(jù)(Uri);
  • category:關(guān)于目標(biāo)組件的信息;
  • component:目標(biāo)組件的類名;
  • extras :這是Bundle數(shù)據(jù)。

Intent解析:

  • 顯式Intent,指定了目標(biāo)組件的類名,即component,則已知目標(biāo)組件,不需解析;
  • 隱式Intent,未指定目標(biāo)組件component,或者不知道、不關(guān)心誰來接收Intent,需要Android自己去解析找到目標(biāo)組件。

隱式Intent解析方法:

1.在AndroidManifest.xml里所有<intent-filter>及其中定義的Intent;
2.通過PackageManager(獲取當(dāng)前設(shè)備所安裝的應(yīng)用程序package)查找能處理這個Intent的component。匹配Action、type、category三個變量來尋找。
二、簡單解釋:
Intent可以激活A(yù)ndorid的三大組件:Activity、Service和BroadcastReceiver。使用Intent時一般要顯式指定目標(biāo)組件,若未指定則要根據(jù)Intent附帶的action、type、category三個值來解析,查找能處理的組件。

三、問題:Intent如何實現(xiàn)組件的切換,具體流程?
1、基本方法:(以啟動Activity為例)

Intent i = new Intent(MainActivity.this, TargetActivity.class);
startActivity(i);

2、實例化Intent:

/**
* 創(chuàng)建一個Intent,直接指定Intent要激活的**組件類名**,而不用依賴**系統(tǒng)去解析**合適的類來處理intent
* @param packageContext 要執(zhí)行這個intent的context對象
* @param cls intent要激活的組件類名
*/
public Intent(Context packageContext, Class cls) {
//創(chuàng)建一個組件并賦值給Intent的Component成員
  mComponent = new ComponentName(packageContext, cls);
}

3、啟動Activity

startActivity(i) ->
startActivity(Intent intent, @Nullable Bundle options)->
startActivityForResult(intent, -1, options)


/** 
*startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options)
* 加載一個Activity并獲取結(jié)果
* @param intent 要啟動的intent.
* @param requestCode 如果大于0則會被返回,且只有返回值返回成功后才會顯示視圖
* @param options 其他信息.
*/
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) { //如果沒有父Activity;Instrumentation是用來與程序指南清單AndroidManifest文件交互的。
  Instrumentation.ActivityResult ar =
  mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options); //執(zhí)行startActivity命令
..... 
} else { //如果有父Activity
   if (options != null) {
     mParent.startActivityFromChild(this, intent, requestCode, options);
   } .....
}

4、執(zhí)行startActivity命令核心代碼:
啟動Activity的任務(wù)交給了底層ActivityManagerNative來做。

intent.migrateExtraStreamToClipData(); //將intent里的bundle數(shù)據(jù)進行處理以便給底層處理
intent.prepareToLeaveProcess(); //準(zhǔn)備離開應(yīng)用程序進程,進入ActivityManagerService進程(意味著bundle的數(shù)據(jù)要在進程間傳遞)
int result = ActivityManagerNative.getDefault().startActivity(whoThread,   
who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options); //調(diào)用系統(tǒng)的activity manager服務(wù)來啟動新的Activity??紤]如果是顯式Intent,則直接找對對應(yīng)的組件類(此處是Activity組件);如果是隱式Intent,為指定目標(biāo)組件類名,則自動去Application->system搜索合適的組件來處理。
//todo:具體的系統(tǒng)級代碼下次進行分析

四、核心問題:為何Intent不能直接在組件間傳遞對象而要通過序列化機制?
根據(jù)上面代碼可以看到,Intent在啟動其他組件時,會離開當(dāng)前應(yīng)用程序進程,進入ActivityManagerService進程(intent.prepareToLeaveProcess()),這也就意味著,Intent所攜帶的數(shù)據(jù)要能夠在不同進程間傳輸。首先我們知道,Android是基于Linux系統(tǒng),不同進程之間的java對象是無法傳輸,所以我們此處要對對象進行序列化,從而實現(xiàn)對象在 應(yīng)用程序進程 和 ActivityManagerService進程 之間傳輸。
而Parcel或者Serializable都可以將對象序列化,其中,Serializable使用方便,但性能不如Parcel容器,后者也是Android系統(tǒng)專門推出的用于進程間通信等的接口。

附加知識:
在不同進程之間,常規(guī)數(shù)據(jù)類型可以直接傳遞,如整數(shù),以傳遞字符串為例,要從A進程傳遞到B進程,只需在B進程的內(nèi)存區(qū)開辟一樣大小的空間,然后復(fù)制過去即可。
但是,對象卻不能直接跨進程傳遞。即使成員變量值能傳遞過去,成員方法是無法傳遞過去的,此時如果B進程要調(diào)用成員方法則出錯。
具體傳遞對象的方法:
1. 在進程A中把類中的非默認(rèn)值的屬性和類的唯一標(biāo)志打成包(這就叫序列化);
2. 把這個包傳遞到進程B;
3. 進程B接收到包后,根據(jù)類的唯一標(biāo)志把類創(chuàng)建出來(java反射機制);
4. 然后把傳來的屬性更新到類對象中。
這樣進程A和進程B中就包含了兩個完全一樣的類對象。

五、Intent如何實現(xiàn)對象傳遞?
Object implements Serializable {...};bundle.putSerializable(Key, Object);
Object implements Parcelable {...} ; bundle.putParcelable(Key, Object);
Serializable接口:這是Java的序列化技術(shù),將Java對象序列化為二進制文件。讓對象實現(xiàn)Serializable接口,使用ObjectInputStream 和 ObjectOutputStream 進行對象讀寫。
Parcelable接口:這是Android提供的用作封裝數(shù)據(jù)的容器,封裝后的數(shù)據(jù)可以通過Intent或IPC來傳遞。只有基本類型和實現(xiàn)了Parcelable接口的類才能被放入Parcel中。
六、Serializable接口 - Java
屬于java序列化機制:只需讓java類實現(xiàn)該接口,不用實現(xiàn)任何方法,即可標(biāo)記該類可序列化。

class Person implements Serializable {...}
Person per = new Person();
bundle.putSerializable("person", per); //傳遞Person對象的引用

Person mPerson = (Person)getIntent().**getSerializableExtra**("person");

注意:如果此處序列化類Person內(nèi)部包含其他類(如:PersonInfo)的引用,如:

class Person implements Serializable {
   PersonInf**o info;
}

那么所引用的類必須也可序列化,即實現(xiàn)Serializable接口。因為Person對象在序列化過程中,也會對成員變量序列化。

七、Parcelable接口 - Android
此處圍繞 - Android中如何使用Parcel實現(xiàn)對象的傳遞 - 簡單介紹一下原因。
首先要了解Android里面的Parcel容器。

Parcel是一個容器,用來存儲可通過IBindler傳送的消息(數(shù)據(jù)或?qū)ο笠茫?br /> 主要用于輕量級、高性能IPC進程間通信的消息容器。在Android里,一個“process”是一個標(biāo)準(zhǔn)Linux進程,一般而言一個進程無法接觸到另一個進程的內(nèi)存區(qū)。而通過Parcel,Android系統(tǒng)會將對象分解成可序列化與反序列化,從而實現(xiàn)進程間通信。
不過,Parcel同樣可用于進程內(nèi)通信,主要實現(xiàn)在應(yīng)用程序的不同組件之間傳遞數(shù)據(jù)。例如,我們可以使用Intent封裝Parcel對象在Activity之間傳遞。
簡單來說,Parcel容器實現(xiàn)了進程內(nèi)與進程間通信,而且還能實現(xiàn)遠(yuǎn)程調(diào)用。

組件間傳遞對象的具體方法:

讓要傳遞的對象所屬類實現(xiàn) Parcelable 接口;
實現(xiàn) describeContents 方法;
實現(xiàn)抽象方法 writeToParcel,用于獲取對象的當(dāng)前狀態(tài)并寫入一個Parcel容器中;
給該目標(biāo)類添加一個靜態(tài)域 CREATOR ,它是一個實現(xiàn)了Parcelable.Creator接口的對象;
添加一個參數(shù)為一個Parcel對象的構(gòu)造函數(shù),CREATOR會調(diào)用這個構(gòu)造函數(shù)來重新改造我們的對象。
問題:
為什么已經(jīng)有了Java的Serializable接口還要創(chuàng)建一個Parcelable接口?
性能
雖然Parcelable使用起來更復(fù)雜一點,但是它的性能更好。

Parcelable的限制:

當(dāng)使用Parcelable來傳遞圖片Bitmap時不太理想,雖然Bitmap也實現(xiàn)了Parcelable接口。比較優(yōu)的方法是傳遞
Parcelable不能用來當(dāng)做常規(guī)的序列化存儲,因為Android系統(tǒng)版本不同,Parcelable的具體實現(xiàn)方法也不完全一樣,可能導(dǎo)致無法讀取Parcel數(shù)據(jù)。

相關(guān)文章

最新評論