意圖和意圖過濾器Intents and Intent Filtersandroid
一個應用程序的三個核心組件-活動,服務和廣播接收器是經過消息即意圖(Intents)來激活的。Intent消息傳送是相同或不一樣應用中組件運行時晚綁定的一種機制。意圖自己,一個意圖對象,是一個包含被執行操做抽象描述的被動的數據結構-或者,對於廣播而言,是某件已經發生並被聲明的事情的描述。存在不一樣的機制來傳送意圖到每種組件中:瀏覽器
一個意圖對象是傳遞給Context.startActivity()或者Activity.startActivityForResult()來啓動一個活動或者讓一個存在的活動去作某些新的事情。
一個意圖對象是傳遞給Context.startService()來發起一個服務或者遞交新的指令給運行中的服務。相似的,一個意圖能被傳遞給Context.bindService() 來在調用組件和一個目標服務之間創建鏈接。做爲一個可選項,它能夠發起這個服務若是還沒運行的話。
傳遞給任意廣播方法(例如Context.sendBroadcast(),Context.sendOrderedBroadcast(), 或者Context.sendStickyBroadcast())的意圖對象被傳遞給全部感興趣的廣播接收者。許多種廣播產生於系統代碼。
在每一個例子裏,Android系統找到合適的活動,服務,或者一組廣播接收者來回應這個意圖,必要時實例化它們。這些消息傳送系統沒有重疊:廣播意圖僅被傳遞給廣播接收者,永遠不會給活動或者服務。一個傳送給startActivity()的意圖是隻會被傳遞給一個活動,永遠不會給一個服務或廣播接收者,如此類推。安全
這篇文檔以意圖對象的描述開始,而後描述Android映射意圖到組件的規則-如何解決哪一個組件應該接收一個意圖消息。對於沒有顯式命名一個目標組件的意圖,這個過程包括對照與潛在目標相關聯的意圖過濾器來測試這個意圖對象。服務器
意圖對象Intent Objects網絡
一個意圖Intent對象是一堆信息。它包含接收這個意圖的組件感興趣的信息(例如將要採起的動做和操做的數據)再加上Android系統感興趣的信息(例如應該處理這個意圖的組件類別和如何啓動一個目標活動的指令):數據結構
組件名稱Component nameapp
應該處理這個意圖的組件名字. 這個字段是一個ComponentName對象- 一個組合物:目標組件的徹底合格的類名 (好比"com.example.project.app.FreneticActivity") 以及應用程序描述文件中設置的組件所在包的名字(好比, "com.example.project"). 這個組件名字的包部分和描述文件中設置的包名字不必定要匹配。ide
組件名字是可選的。若是被設置了,這個意圖對象將被傳遞到指定的類。若是沒有, Android使用另外的意圖對象中的信息去定位一個合適的目標- 請看本文稍後描述的意圖解析Intent Resolution。測試
組件名字經過以下方法:setComponent(),setClass(), 或者setClassName()設置並經過getComponent()讀取。.net
動做Action
一個將被執行的動做的字符串命名-或者, 對於廣播意圖而言, 是發生並被報告的動做。這個意圖類定義了一些動做常量, 包含下面這些:
常量
目標組件
Action
ACTION_CALL
活動
開始一個電話呼叫
ACTION_EDIT
活動
顯示數據以給用戶編輯
ACTION_MAIN
活動
開始任務的初始活動,沒有輸入數據也沒有輸出返回
ACTION_SYNC
活動
同步服務器與移動設備之間的數據
ACTION_BATTERY_LOW
廣播接收器
電池低電量警告
ACTION_HEADSET_PLUG
廣播接收器
耳機插拔
ACTION_SCREEN_ON
廣播接收器
屏幕開啓
ACTION_TIMEZONE_CHANGED
廣播接收器
時區變化
經過查看Intent類描述可得到一個通用動做的預約義常量列表。其餘動做被定義在Android API的其餘地方。你也能夠自定義動做字符串來激活應用程序中的組件。那些你所建立的動做字符串應該以應用程序包名做爲前綴-例如:
"com.example.project.SHOW_COLOR".
動做很大程度上決定了意圖其餘部分如何被組織-尤爲是數據data和附加字段extras-很像一個方法名決定了一些參數和返回值. 所以, 一個好的想法是使用盡量具體的動做名並和意圖的其餘字段緊密聯繫起來。換句話說,爲您的組件能處理的意圖對象定義一個總體的協議而不是定義一個孤立的動做。
一個意圖對象裏的動做能夠經過setAction()方法設置和經過getAction()方法讀取.
數據Data
想要操做的數據統一資源標識符(URI)和那種數據的多用途互聯網郵件擴展(MIME). 不一樣的動做伴隨着不一樣種類的數據規格。例如,若是動做是ACTION_EDIT,數據字段會包含可編輯文檔的URI;若是動做是ACTION_CALL,數據字段會是一個電話號碼:含呼叫電話號碼的URI;相似的,若是動做是ACTION_VIEW並且數據字段是一個http:URI, 那麼接收到的活動將會是下載並顯示URI所引用數據的請求。當匹配一個意圖到一個能處理數據的組件時,除了它的URI外,一般須要知道數據類型(它的MIME類型)。
好比,一個能顯示圖片的組件不該該被要求去播放一個聲音文件。
在不少狀況下,這個數據類型能夠從URI裏推斷出來-尤爲是content:URIs, 這意味着數據被存放在設備上並且由一個內容提供者控制着。(參閱separate discussion on content providers). 但類型能夠在乎圖對象裏顯示的設置。setData()方法指定數據只能爲一個URI,setType()指定它只能是一個MIME類型, 而setDataAndType()指定它同時爲URI和MIME類型。URI經過getData()讀取,類型則經過getType().
目錄Category
一個包含關於應該處理這個意圖的組件的附加信息的字符串。任意數目的類別描述能夠被放到一個意圖對象裏。和動做同樣,意圖類定義若干類別常量,包含以下這些:
常量
含義
CATEGORY_BROWSABLE
目標活動能夠被瀏覽器安全的喚起來顯示被一個連接所引用的數據-好比,一張圖片或一條e-mail消息。
CATEGORY_GADGET
這個活動能夠被嵌入到充當配件宿主的另外的活動裏面。
CATEGORY_HOME
這個活動將顯示桌面,也就是用戶開機後看到的第一個屏幕或者按HOME鍵時看到的屏幕。
CATEGORY_LAUNCHER
這個活動能夠是一個任務的初始活動並被列在應用程序啓動器的頂層。
CATEGORY_PREFERENCE
目標活動是一個選擇面板。
查閱Intent類描述可獲取類別的完整列表。
addCategory()方法在一個意圖對象中添加了一個目錄,removeCategory()刪除以前添加的目錄,而getCategories()能夠獲取當前對象的全部類別。
附加信息Extras
應該遞交給意圖處理組件的附加信息鍵-值對。就像一些動做伴隨着特定的數據URIs類型,一些動做則伴隨着特定的附加信息。好比,一個ACTION_TIMEZONE_CHANGED意圖有一個「時區」附加信息用來區別新的時區,而ACTION_HEADSET_PLUG有一個「狀態」附加字段代表耳機有沒有插着,以及一個「名字」附加信息來表示耳機的類型。若是你想要建立一個SHOW_COLOR動做,顏色的值將被設置在一個附加的鍵-值對中。
意圖對象有一系列的put...()方法來插入各類不一樣的附加數據和一個相似的用來讀取數據的get...()方法系列。這些方法與Bundle對象的方法類似。事實上,附加信息能夠被看成一個Bundle經過使用putExtras()和getExtras()方法安裝和讀取。
標誌Flags
各類類型的標誌. 許多標誌用來指示Android系統如何去加載一個活動(例如,哪一個是這個活動應該歸屬的任務)和啓動後如何對待它(好比,它是否屬於當前活動列表),全部這些列表都在乎圖類中定義了。
Android系統以及這個平臺上的應用程序利用意圖對象來發送源於系統的廣播以及激活系統定義的組件。要查閱如何組織一個意圖去激活一個系統組件,請諮詢引用中的意圖列表list of intents。
意圖解析Intent Resolution
意圖能夠被分紅兩組:
顯式意圖 經過名字指明目標組件(這個組件名字字段component name field, 前面提到過, 有一個數值集)。既然組件名稱一般不爲其餘應用程序的開發者所瞭解,顯式意圖典型的被用做應用程序的內部消息-例如一個活動啓動一個附屬服務或姊妹活動。
隱式意圖 不命名目標組件(組件名稱字段爲空)。隱式意圖常常用來激活其餘應用程序的組件。
Android遞交一個顯式的意圖給一個指定目標類的實例。意圖對象中的組件名稱惟一的肯定哪一個組件應該獲取這個意圖。隱式意圖須要一個不一樣的策略。在沒有指定目標的狀況下,Android系統必須找到最合適的組件來處理這個意圖-單個活動或者服務來執行這個請求動做或者一系列的廣播接收器來應對廣播通告。
這是經過比較意圖對象的內容和意圖過濾器,有可能接收意圖的組件相關結構。過濾器公佈一個組件具有的能力以及限定它能處理的意圖。他們使組件接收該公佈類型的隱式意圖成爲可能。若是一個組件沒有任何的意圖過濾器,那它只能接收顯式意圖。一個帶過濾器的組件能夠同時接收顯式和隱式意圖。
當一個意圖對象被一個意圖過濾器測試時,只有三個方面會被參考到:
動做
數據(URI以及數據類型)
類別
附加信息和標誌並不參與解析哪一個組件接收一個意圖。
意圖過濾器Intent filters
爲了通知系統它們能夠處理哪些意圖,活動、服務和廣播接收器能夠有一個或多個意圖過濾器。每一個過濾器描述組件的一個能力,一系列組件想要接收的意圖。它實際上按照一個指望的類型來進行意圖濾入,同時濾出不想要的意圖-可是隻有不想要的隱式意圖會被濾出(那些沒有命名目標的對象類)。一個顯式意圖總可以被遞交給它的目標,而不管它包含什麼。這種狀況下過濾器不起做用。可是一個顯式意圖僅當它能經過組件的一個過濾器時才能夠被遞交到這個組件。
組件爲它能作的每項工做,每一個呈現給用戶的不一樣方面分有不一樣的過濾器。好比,範例記事本應用程序中的主要活動有三個過濾器-一個是空白板,另外一個是用戶能夠查看、編輯、或選擇的一個指定的記事目錄,第三是在沒有初始目錄說明的狀況下查找一個特定的記錄。一個意圖過濾器是IntentFilter類的一個實例。可是,因爲Android系統在啓動一個組件前必須知道這個組件的能力,意圖過濾器一般不會用Java代碼來設置,而是在應用程序清單文件(AndroidManifest.xml)中設置
過濾器與安全Filters and security
不能信賴一個意圖過濾器的安全性。當它打開一個組件來接收某些特定類型的隱式意圖,它並不能阻止以這個組件爲目標的顯式意圖。即便過濾器對組件要處理的意圖限制某些動做和數據源,總有人能把一個顯式意圖和一個不一樣的動做及數據源組合在一塊兒,而後命名該組件爲目標。
一個過濾器和意圖對象有一樣的動做、數據以及類別字段。一個隱式意圖在過濾器的全部三個方面都被測試。爲了遞交到擁有這個過濾器的組件,它必須經過全部這三項測試。即使只有一個不經過,Android系統都不會把它遞交給這個組件-至少以那個過濾器的標準而言。不過,因爲一個組件能夠包含多個意圖過濾器,一個不能經過其中一個組件過濾器的意圖可能在另外的過濾器上得到經過。
三個測試詳細描述以下:
動做測試Action test
清單文件中的意圖過濾器元素裏列舉了動做元素,好比:
. . .
如同例子所示,一個意圖對象只對單個動做命名,而一個過濾器可能列舉多個。列表不能爲空;一個過濾器必須包含至少一個動做元素,不然它將阻塞全部的意圖。
爲了經過這個測試,在乎圖對象中指定的動做必須匹配過濾器中所列舉的動做之一。若是意圖對象或過濾器不指定一個動做,結果將以下:
· 若是這個過濾器沒有列出任何動做,那意圖就沒有什麼可匹配的,所以全部的意圖都會測試失敗。沒有意圖可以經過這個過濾器。
· 另外一方面,一個未指定動做的意圖對象自動經過這個測試-只要過濾器包含至少一個動做。
類別測試Category test
一個意圖過濾器
. . .
注意前面描述的動做和類別常量沒有在清單文件中使用。相反使用了完整的字符串。好比,對應於前述CATEGORY_BROWSABLE常量,上面的例子裏使用了"android.intent.category.BROWSABLE"字符串。相似的,字符串"android.intent.action.EDIT" 對應於ACTION_EDIT常量。
對一個經過類別測試的意圖,每一個意圖對象中的類別必須匹配一個過濾器中的類別。這個過濾器能夠列舉另外的類別,但它不能遺漏任何在這個意圖中的類別。
所以,原則上一個沒有類別的意圖對象應該總可以經過測試,而無論過濾器裏有什麼。絕大部分狀況下這個是對的。但有一個例外,Android把全部傳給startActivity()的隱式意圖看成他們包含至少一個類別:"android.intent.category.DEFAULT" (CATEGORY_DEFAULT常量)。 所以,想要接收隱式意圖的活動必須在它們的意圖過濾器中包含"android.intent.category.DEFAULT"。(帶"android.intent.action.MAIN"和"android.intent.category.LAUNCHER"設置的過濾器是例外)。它們標記那些啓動新任務和呈如今啓動屏幕的活動。它們能夠在類別列表中包含"android.intent.category.DEFAULT",但不是必要的。) 可查閱後面的使用意圖匹配(Using intent matching)以得到更多關於過濾器的信息。
數據測試Data test
就像動做和類別,一個意圖過濾器的數據規格被包含在一個子元素中。並且這個子元素能夠出現屢次或一次都不出現。例如:
. . .
每一個數據元素能夠指定一個URI和一個數據類型(MIME媒體類型)。有一些單獨的屬性-模式,主機,端口和路徑-URI的每一個部分:
scheme://host:port/path
好比,在下面的URI裏面,
content://com.example.project:200/folder/subfolder/etc
模式是"內容",主機是"com.example.project",端口是"200",路經是"folder/subfolder/etc"。主機和端口一塊兒組成URI鑑權(authority);若是未指定主機,端口會被忽略。
這些屬性都是可選的,但彼此有依賴關係:一個受權要有意義,必須指定一個模式。一個路經要有意義,必須同時指定模式和鑑權。
當一個意圖對象中的URI被用來和一個過濾器中的URI規格比較時,它實際上比較的是上面提到的URI的各個部分。好比,若是過濾器僅指定了一個模式,全部那個模式的URIs和這個過濾器相匹配;若是過濾器指定了一個模式、鑑權但沒有路經,全部相同模式和鑑權的URIs能夠匹配上,而無論它們的路經;若是過濾器指定了一個模式、鑑權和路經,只有相同模式、鑑權和路經的URIs能夠匹配上。固然,一個過濾器中的路徑規格能夠包含通配符,這樣只須要部分匹配便可。
數據元素的類型屬性指定了數據的MIME類型。這在過濾器裏比在URI裏更爲常見。意圖對象和過濾器均可以使用一個"*"通配符指定子類型字段-好比,"text/*"或者"audio/*"-指示任何匹配的子類型。
數據測試同時比較意圖對象和過濾器中指定的URI和數據類型。規則以下:
a. 一個既不包含URI也不包含數據類型的意圖對象僅在過濾器也一樣沒有指定任何URIs和數據類型的狀況下才能經過測試。
b. 一個包含URI但沒有數據類型的意圖對象僅在它的URI和一個一樣沒有指定數據類型的過濾器裏的URI匹配時才能經過測試。這一般發生在相似於mailto:和tel:這樣的URIs上:它們並不引用實際數據。
c. 一個包含數據類型但不包含URI的意圖對象僅在這個過濾器列舉了一樣的數據類型並且也沒有指定一個URI的狀況下才能經過測試。
d. 一個同時包含URI和數據類型(或者可從URI推斷出數據類型)的意圖對象能夠經過測試,若是它的類型和過濾器中列舉的類型相匹配的話。若是它的URI和這個過濾器中的一個URI相匹配或者它有一個內容content:或者文件file: URI並且這個過濾器沒有指定一個URI,那麼它也能經過測試。換句話說,一個組件被假定爲支持content:和file: 數據若是它的過濾器僅列舉了一個數據類型。
若是一個意圖能夠經過不止一個活動或服務的過濾器,用戶可能會被詢問要激活那個組件。若是沒有發現目標對象將會出現異常。
一般狀況Common cases
上面描述的數據測試的最後一個規則(d),表達了這樣一個指望即組件可以從文件或內容提供者中獲取本地數據。所以,它們的過濾器能夠只列舉一個數據類型而不須要顯式的命名content:和file:模式。這是一個典型狀況。好比,一個以下的數據元素,告訴Android這個組件能從內容提供者獲取圖片數據並顯示:
既然大多數可用數據是經過內容提供者來分發,那麼過濾器最一般的配置就是指定一個數據類型而不指定URI。另一個通用的配置是帶有一個模式和數據類型的過濾器。好比,一個以下的數據元素告訴Android能夠從網絡獲取視頻數據並顯示:
好比,想一下,當用戶點擊網頁上的一個連接時瀏覽器作了什麼。它首先試圖去顯示這個數據(若是這個連接指向一個HTML頁面)。若是它不能顯示這個數據,它會把一個顯式意圖和一個模式、數據類型組成總體而後嘗試啓動一個能夠處理這個工做的活動。若是沒有接受者,它將要求下載管理器來下載數據。這讓它處於內容提供者的控制下,以便一個潛在的更大的活動池能夠作出反應。
大多數應用程序一樣有一個方法去啓動刷新,而不包含任何特定數據的引用。能初始化應用程序的活動擁有指定動做爲"android.intent.action.MAIN"的過濾器。若是它們表述在應用程序啓動器中,那它們一樣指定了"android.intent.category.LAUNCHER"類別:
使用意圖匹配Using intent matching
經過意圖過濾器匹配的意圖不只是爲了發現要激活的目標組件,並且爲了發現這個設備上的一系列組件的某些東西。好比,Android系統經過查找符合條件的全部活動(須要包含指定了動做"android.intent.action.MAIN"和"android.intent.category.LAUNCHER"類別的意圖過濾器,如前面章節所述)來產生應用程序啓動器,也就是用戶可用程序的前置屏幕。而後它顯示在這個啓動器裏的這些活動的圖標和標籤。相似的,它經過查找其過濾器配有"android.intent.category.HOME"元素的活動來發現桌面。
你的應用程序能夠用相似的方式使用意圖匹配。PackageManager有一系列的查詢query…()方法能夠接收一個特定的意圖,以及類似的一個解析resolve…()方法系列能夠肯定應答意圖的最佳組件。好比,queryIntentActivities()返回一個全部活動的列表,而queryIntentServices()返回一個相似的服務列表。兩個方法都不會激活組件;它們僅僅列舉能應答的。對於廣播接收者,有一個相似的方法queryBroadcastReceivers()。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/iefreer/archive/2009/08/17/4456376.aspx