什麼是Intent
java
Intent是一種運行時綁定(run-time binding)機制,它能在程序運行過程當中鏈接兩個不一樣的組件。經過Intent,你的程序能夠向Android表達某種請求或者意願,Android會根據意願的內容選擇適當的組件來完成請求。好比,有一個Activity但願打開網頁瀏覽器查看某一網頁的內容,那麼這個Activity只須要發出WEB_SEARCH_ACTION給Android,Android就會根據Intent的請求內容,查詢各組件註冊時聲明的IntentFilter,找到網頁瀏覽器的Activity來瀏覽網頁。android
Android的三個基本組件——Activity,Service和Broadcast Receiver——都是經過Intent機制激活的,不一樣類型的組件有不一樣的傳遞Intent方式:數據庫
要激活一個新的Activity,或者讓一個現有的Activity作新的操做,能夠經過調用Context.startActivity()或者Activity.startActivityForResult()方法。瀏覽器
要啓動一個新的Service,或者向一個已有的Service傳遞新的指令,調用Context.startService()方法或者調用Context.bindService()方法將調用此方法的上下文對象與Service綁定。服務器
Context.sendBroadcast()、Context.sendOrderBroadcast()、Context.sendStickBroadcast()這三個方法能夠發送Broadcast Intent。發送以後,全部已註冊的而且擁有與之相匹配IntentFilter的BroadcastReceiver就會被激活。app
Intent一旦發出,Android都會準確找到相匹配的一個或多個Activity,Service或者BroadcastReceiver做響應。因此,不一樣類型的Intent消息不會出現重疊,即Broadcast的Intent消息只會發送給BroadcastReceiver,而決不會發送給Activity或者Service。由startActivity()傳遞的消息也只會發給Activity,由startService()傳遞的Intent只會發送給Service。
ide
Intent的構成
函數
要在不一樣的activity之間傳遞數據,就要在intent中包含相應的內容,通常來講數據中最基本的應該包括:
工具
Action:用來指明要實施的動做是什麼,好比說ACTION_VIEW, ACTION_EDIT等。具體的能夠查閱android SDK-> reference中的Android.content.intent類,裏面的constants中定義了全部的action。
一些經常使用的Action:
ACTION_CALL activity 啓動一個電話.
ACTION_EDIT activity 顯示用戶編輯的數據.
ACTION_MAIN activity 做爲Task中第一個Activity啓動
ACTION_SYNC activity 同步手機與數據服務器上的數據.
ACTION_BATTERY_LOW broadcast receiver 電池電量太低警告.
ACTION_HEADSET_PLUG broadcast receiver 插拔耳機警告
ACTION_SCREEN_ON broadcast receiver 屏幕變亮警告.
ACTION_TIMEZONE_CHANGED broadcast receiver 改變時區警告.
ui
Data: 要事實的具體的數據,通常由一個Uri變量來表示
簡單的Action,Data的例子:
[java] view plaincopy
Uri uri = Uri.parse("http://www.google.com");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
Category:一個字符串,包含了關於處理該intent的組件的種類的信息。一個intent對象能夠有任意個category。intent類定義了許多category常數:
CATEGORY_BROWSABLE 目標activity可使用瀏覽器來顯示-例如圖片或電子郵件消息
CATEGORY_GADGET 該activity能夠被包含在另一個裝載小工具的activity中
CATEGORY_HOME 該activity顯示主屏幕,也就是用戶按下Home鍵看到的界面
CATEGORY_LAUNCHER 該activity能夠做爲一個Task的第一個activity,而且列在應用程序啓動器中
CATEGORY_PREFERENCE 該activity是一個選項面板
addCategory()方法爲一個intent對象增長一個category,
removeCategory刪除一個category,
getCategories()獲取intent全部的category.
Type:顯式指定Intent的數據類型(MIME)(多用途互聯網郵件擴展,Multipurpose Internet Mail Extensions)。好比,一個組件是能夠顯示圖片數據的而不能播放聲音文件。不少狀況下,data類型可在URI中找到,好比content:開頭的URI,代表數據由設備上的content provider提供。可是經過設置這個屬性,能夠強制採用顯式指定的類型而再也不進行推導。
component:指定Intent的目標組件的類名稱。一般 Android會根據Intent 中包含的其它屬性的信息,好比action、data/type、category進行查找,最終找到一個與之匹配的目標組件。可是,若是 component這個屬性有指定的話,將直接使用它指定的組件,而再也不執行上述查找過程。指定了這個屬性之後,Intent的其它全部屬性都是可選的。例如:
[java] view plaincopy
Intent it = new Intent(Activity.Main.this, Activity2.class);
startActivity(it);
extras:附加信息,例如ACTION_TIMEZONE_CHANGED的intent有一個"time-zone"附加信息來指明新的時區,而ACTION_HEADSET_PLUG有一個「state」附加信息來指示耳機是被插入仍是被拔出。intent對象有一系列put...()和set...()方法來設定和獲取附加信息。 這些方法和Bundle對象很像。事實上附加信息可使用putExtras()和getExtras()做爲Bundle來讀和寫。例如:
[java] view plaincopy
//用Bundle傳遞數據
Intent it = new Intent(Activity.Main.this, Activity2.class);
Bundle bundle=new Bundle();
bundle.putString("name", "This is from MainActivity!"); it.putExtras(bundle);
startActivity(it);
//得到數據
Bundle bundle=getIntent().getExtras();
String name=bundle.getString("name");
intent的解析
在應用中,咱們能夠以兩種形式來使用Intent:
直接Intent(或名顯示intent):指定了component屬性的Intent(調用setComponent(ComponentName)或者setClass(Context, Class)來指定)。經過指定具體的組件類,通知應用啓動對應的組件。
間接Intent(或名隱式intent):沒有指定comonent屬性的Intent。這些Intent須要包含足夠的信息,這樣系統才能根據這些信息,在在全部的可用組件中,肯定知足此Intent的組件。
對於直接Intent,Android不須要去作解析,由於目標組件已經很明確,Android須要解析的是那些間接Intent,經過解析將 Intent映射給能夠處理此Intent的Activity、Service或Broadcast Receiver。
Intent解析機制主要是經過查找已註冊在AndroidManifest.xml中的全部<intent-filter>及其中定義的Intent,經過PackageManager(注:PackageManager可以獲得當前設備上所安裝的
application package的信息)來查找能處理這個Intent的component。在這個解析過程當中,Android是經過Intent的action、type、category這三個屬性來進行判斷的,判斷方法以下:
若是Intent指明定了action,則目標組件的IntentFilter的action列表中就必須包含有這個action,不然不能匹配;
若是Intent沒有提供type,系統將從data中獲得數據類型。和action同樣,目標組件的數據類型列表中必須包含Intent的數據類型,不然不能匹配。
若是Intent中的數據不是content:類型的URI,並且Intent也沒有明確指定type,將根據Intent中數據的scheme(好比 http:或者mailto:)進行匹配。同上,Intent 的scheme必須出如今目標組件的scheme列表中。
若是Intent指定了一個或多個category,這些類別必須所有出如今組建的類別列表中。好比Intent中包含了兩個類別:LAUNCHER_CATEGORY和ALTERNATIVE_CATEGORY,解析獲得的目標組件必須至少包含這兩個類別。
相信作android應用開發的朋友對intent組件都已是至關熟悉了,這裏鄙人總結一下intent的妙用,但願對你們有幫助。
intent妙用之編寫本身的android主界面
衆所周知,android的主界面名爲laucher2,功能強大,會在android啓動以後運行,也是全部其餘應用程序的入口程序。那麼,如何讓本身的應用程序取代laucher2的位置,成爲android系統的主界面呢?其實說出來很簡單,接下來,我就來爲你們揭開這其中的神祕面紗。
首先,咱們來看看一個普通的應用程序的intent聲明:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
是否是看着很眼熟呢?沒錯了,這段代碼是在AndroidManifest.xml中相應activity的intent聲明,相信你們目前縮寫的應用程序的intent聲明無一例外都是這樣的吧。可能不少人都會對着兩行代碼有下面的理解:
第二行<action android:name="android.intent.action.MAIN" />表示這個activity是當前應用程序的主activity,而第二行表示當前activity在lancher中加載。
這麼理解的倒是沒錯,但事實上,有更加簡單的理解方式。這裏請允許我先賣個關子。咱們繼續往下看。
既然是想讓咱們本身的應用程序取代laucher的位置,那麼咱們就來看一下lancher的intent聲明是怎麼樣的吧:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY" />
</intent-filter>
固然,想要看到這段代碼,你必需要有laucher的源代碼。(關於android源代碼的問題,前面的文章已經提到過不少次了,有源代碼真的是件很好的事情,無論是對應用程序開發者來講仍是對底層開發者來講亦或是對android愛好者來講,都會受益不淺的,因此這裏再次建議你們不要僅僅侷限於android sdk和avd的使用來進行應用程序的開發,無論你有沒有時間,下份源代碼老是沒有壞處的。)
你們看出這兩個intent聲明之間的差異了嗎?沒錯,當出現 <category android:name="android.intent.category.HOME"/> 的時候,咱們的應用程序就會變成跟lancher具備相同功能的(固然,我指的僅僅是主界面,laucher的功能是在是太強大了),成爲android系統的主界面,而且,當咱們按下Home鍵的時候,會出現一個選擇界面,是否是發現你的應用程序和laucher同時出如今了選擇框中呢?若是是,那麼恭喜你,從功能上來講,你已經實現了。若是沒有看到,請email我louiswangbing@gmail.com。
可是,所謂一山不容二虎,同時有兩個主界面存在固然不是咱們想要的。
若是你有android源代碼的話,你甚至能夠把laucher刪掉,直接將你本身的應用程序編譯到android系統中,這樣,系統啓動的時候就會直接運行你的應用程序,而你的應用程序就會冠冕堂皇地鳩佔鵲巢,瓜熟蒂落的成爲系統的主界面,而且當你按下Home鍵的時候,就會跳到你的應用程序的主activity了!!
若是你只是一個功能上的追求者,那麼看到這裏你就能夠關掉這個頁面去試試上面的功能了。
若是你是一個好奇心比較強的人,那麼請跟着我繼續往下看。
剛纔我說過,intent聲明的理解問題。事實上,你能夠有更好的理解方式,固然,這要創建在你對android系統的啓動進程有必定的瞭解的基礎上。
簡單來講,intent其實就是一個條件過濾器,activity的intent聲明的每一條均可以做爲一個過濾條件,條目越多,過濾條件也就越強,定位起來也就越容易。相信這個原理學過數據庫的朋友理解起來更加容易。你能夠將整個android系統中全部的activity都集中起來當成是一個數據庫,而intent自己就是一條select語句,其中每一項聲明都是一項過濾條件,而過濾以後剩下的,就是將要被調用的activity。當過濾條件足夠強大或者過濾條件比較特殊的時候,最後剩下的只有一個activity,那麼系統會絕不猶豫地啓動它;當過濾條件不足致使過濾以後還剩下比較多的activity的時候,系統會將知足這些條件的全部的activity用一個listview列出來讓你選擇。
相信原理你們都已經很清楚了,那麼上面所述的這個功能就很好理解了。沒錯,android在啓動的時候會有一個PackageManager選擇系統中知足過濾條件:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY" />
的activity做爲系統啓動的第一個activity,也就是主界面,任何一個知足這個過濾條件的activity都將進入候選名單,若是候選名單中僅有一人,那麼很榮幸,不戰而勝,你就是系統的主界面了;若是候選名單中有多我的(好比剛纔說的有laucher和你本身的應用程序),那麼就進入殘酷的」民意選舉「,也就是用戶本身的選擇,你選誰系統就會啓動誰。但和民意選舉不一樣的是,選舉出來的結果一般會有必定的任期,而這個主界面的選舉任期很是的短,每當你按下一次Home鍵或者重啓一下系統,系統就會從新安排一次」民意選舉「。若是想要永遠的成爲主界面,那麼惟一的辦法就是--沒錯,雖然很殘酷,但不得不說--就是,幹掉它......或者和諧一點,你可讓它活着,可是也必須將它貶爲庶民或者是將其發配邊疆,具體的實施手段就是--改掉它的intent聲明,使其不知足主界面的這個過濾條件。
在整個intent妙用章節中,這一章算是比較特殊的,由於雖然全部的章節運用的原理基本相通,也就是我上面說到的原理,可是後續章節的intent過濾條件都是能夠由用戶本身定義、手動修改的,而惟獨只有這個是不能改的,你只能決定去適應或者不適應這個過濾條件,而不能去改變這個過濾條件,就像你只能去適應這個社會,卻很難改變它--或許不是不能,而是暫時還能找到途徑......
有時候真的,生活跟計算機,竟然有如此之多的類似之處......
intent妙用之列出全部已安裝的應用程序列表
裝載:http://blog.csdn.net/android_tutor/article/details/5724634
這篇文章寫的很好,既說明了方法,也給出了實例,可是很惋惜的是,並無說明其中的原理。
這裏,看過我上一篇文章的朋友相信已經可以本身分析得出答案了!
沒錯,其實全部的這些應用程序列表也就是一個過濾以後知足過濾條件的activity!而這個過濾條件一般是:
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
即對應着上面轉載文章當中的函數:
public void bindAllApps(){
//這裏是關鍵哦,咱們平時寫的應用總有一個activity申明成這兩個屬性
//也就是應用的入口
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
//符合上面條件的所有查出來,而且排序
mAllApps = mPackageManager.queryIntentActivities(mainIntent, 0);
Collections.sort(mAllApps, new ResolveInfo.DisplayNameComparator(mPackageManager));
}
很容易看明白,四、5兩行就是定義的這個過濾條件,其中Intent.ACTION_MAIN對應着<action android:name="android.intent.action.MAIN" />,Intent.CATEGORY_LAUNCHER對應着<category android:name="android.intent.category.LAUNCHER" /> ,這個對應關係是系統定義的。固然,這個對應關係其實也能夠本身自定義,後續章節會介紹,這裏略過。而今跟着的後面兩句就是查詢和列出符合條件的activity了。這裏須要注意到是,並非全部的應用程序intent聲明都能知足這個過濾條件的,好比說你們喜聞樂見的Adobe 的Flashplayer瀏覽器插件就不是這樣的,這也是爲何你們將這個插件安裝到手機上卻不能顯示在主界面應用程序列表裏面的緣由。
帶着我上一篇文章裏面講到的原理,這部分的理解就顯得異常簡單了。
固然啊,到這裏也只是完成了列出全部知足過濾條件的應用列表而已,想要點擊這個列表就能進入相應的應用程序,還有接下來的工做要作。
參照我轉載的這篇文章來講,函數功能是這樣實現的:
//gridview點擊事件,點擊進入相關應用
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// TODO Auto-generated method stub
ResolveInfo res = mAllApps.get(position);
//該應用的包名和主Activity
String pkg = res.activityInfo.packageName;
String cls = res.activityInfo.name;
ComponentName componet = new ComponentName(pkg, cls);
Intent i = new Intent();
i.setComponent(componet);
startActivity(i);
}
在具體說明原理以前,有一個前提條件你們必需要記住,那就是在android系統中,是不容許有兩個包名徹底相同的應用程序存在的,若是兩個程序的包名和包裏面的內容徹底同樣,後來的將會覆蓋原有的,這也是爲何android應用開發不須要卸載以前的應用程序而直接修改源代碼再運行就能夠覆蓋的緣由。
有了這個前提條件以後,接下來,咱們看看這段代碼。其實,這裏也是intent的一個妙用。前面的那些過濾條件,咱們稱之爲隱式intent,由於將會過濾出哪些或者多少知足條件的activity,咱們都是不知道的。而這裏的intent使用,咱們稱之爲顯示intent,由於它的過濾條件十分強大,近似一個指針,直接指向一個獨一無二的應用,而且在指定的時候就已經知道它是誰,並且知道它確定是獨一無二的。
其實很簡單,剛纔已經說過 了,由於android中不容許有相同的包名出現,也就是說全部的包名都是獨一無二的,那麼只要指定intent過濾條件爲相應的包名和activity名,一切也就迎刃而解了。從數據庫原理的角度來理解,列出全部知足條件的列表以後,第N條的數據是什麼已經能夠看見了,這時候只須要將過濾條件設置主鍵值爲第N條的那個主鍵值就能夠惟必定位到那條數據了。
上面的代碼到第13行的時候,intent i所包含的activity就只剩下一個了,剩下的工做只須要啓動它就好了,startActivity(i),一切瓜熟蒂落。